@@ -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 #-}
12+-------------------------------------------------------------------------------
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
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
27+-------------------------------------------------------------------------------
31+module Database.V1.Bloodhound.Types
33+ , defaultIndexSettings
34+ , defaultIndexDocumentSettings
45+ , mkTermsScriptAggregation
47+ , mkCardinalityAggregation
71+ , UpdatableIndexSetting(..)
72+ , IndexSettingsSummary(..)
73+ , AllocationPolicy(..)
80+ , InitialShardCount(..)
90+ , EsProtocolException(..)
93+ , IndexAliasAction(..)
94+ , IndexAliasCreate(..)
95+ , IndexAliasSummary(..)
96+ , IndexAliasesSummary(..)
98+ , SearchAliasRouting(..)
99+ , IndexAliasRouting(..)
102+ , ExternalDocVersion(..)
103+ , VersionControl(..)
104+ , DocumentParent(..)
105+ , IndexDocumentSettings(..)
116+ , PatternOrPatterns(..)
127+ , GeoBoundingBoxConstraint(..)
128+ , GeoBoundingBox(..)
137+ , RangeExecution(..)
145+ , GreaterThanEqD(..)
152+ , IndexSelection(..)
155+ , IndexOptimizationSettings(..)
156+ , defaultIndexOptimizationSettings
158+ , TemplatePattern(..)
172+ , OpenCloseIndex(..)
176+ , MultiMatchQuery(..)
179+ , CommonTermsQuery(..)
182+ , FuzzyLikeThisQuery(..)
183+ , FuzzyLikeFieldQuery(..)
186+ , HasParentQuery(..)
188+ , MoreLikeThisQuery(..)
189+ , MoreLikeThisFieldQuery(..)
192+ , QueryStringQuery(..)
193+ , SimpleQueryStringQuery(..)
197+ , TemplateQueryInline(..)
198+ , TemplateQueryKeyValuePairs(..)
199+ , BooleanOperator(..)
200+ , ZeroTermsQuery(..)
201+ , CutoffFrequency(..)
205+ , MatchQueryType(..)
206+ , MultiMatchQueryType(..)
210+ , CommonMinimumMatch(..)
211+ , MinimumMatchHighLow(..)
214+ , IgnoreTermFrequency(..)
223+ , MaxDocFrequency(..)
224+ , MinDocFrequency(..)
228+ , MinimumTermFrequency(..)
230+ , FieldDefinition(..)
233+ , AllowLeadingWildcard(..)
234+ , LowercaseExpanded(..)
235+ , GeneratePhraseQueries(..)
237+ , AnalyzeWildcard(..)
238+ , EnablePositionIncrements(..)
239+ , SimpleQueryFlag(..)
246+ , CollectionMode(..)
249+ , SnapshotRepoSelection(..)
250+ , GenericSnapshotRepo(..)
252+ , SnapshotRepoConversionError(..)
253+ , SnapshotRepoType(..)
254+ , GenericSnapshotRepoSettings(..)
255+ , SnapshotRepoUpdateSettings(..)
256+ , defaultSnapshotRepoUpdateSettings
257+ , SnapshotRepoName(..)
258+ , SnapshotRepoPattern(..)
259+ , SnapshotVerification(..)
260+ , SnapshotNodeVerification(..)
267+ , NodeBreakersStats(..)
268+ , NodeBreakerStats(..)
270+ , NodeTransportStats(..)
272+ , NodeDataPathStats(..)
273+ , NodeFSTotalStats(..)
274+ , NodeNetworkStats(..)
275+ , NodeThreadPoolsStats(..)
276+ , NodeThreadPoolStats(..)
278+ , JVMBufferPoolStats(..)
281+ , NodeProcessStats(..)
284+ , NodeIndicesStats(..)
288+ , NodePluginInfo(..)
290+ , NodeTransportInfo(..)
291+ , BoundTransportAddress(..)
292+ , NodeNetworkInfo(..)
294+ , NetworkInterfaceName(..)
295+ , NodeNetworkInterface(..)
296+ , NodeThreadPoolsInfo(..)
297+ , NodeThreadPoolInfo(..)
298+ , ThreadPoolSize(..)
299+ , ThreadPoolType(..)
302+ , JVMGCCollector(..)
307+ , NodeProcessInfo(..)
308+ , FsSnapshotRepo(..)
309+ , SnapshotCreateSettings(..)
310+ , defaultSnapshotCreateSettings
311+ , SnapshotSelection(..)
312+ , SnapshotPattern(..)
314+ , SnapshotShardFailure(..)
318+ , SnapshotRestoreSettings(..)
319+ , defaultSnapshotRestoreSettings
320+ , RestoreRenamePattern(..)
321+ , RestoreRenameToken(..)
325+ , RestoreIndexSettings(..)
328+ , PhraseSuggester(..)
329+ , PhraseSuggesterHighlighter(..)
330+ , PhraseSuggesterCollate(..)
332+ , SuggestOptions(..)
333+ , SuggestResponse(..)
334+ , NamedSuggestionResponse(..)
335+ , DirectGenerators(..)
336+ , mkDirectGenerators
337+ , DirectGeneratorSuggestModeTypes (..)
341+ , AggregationResults
344+ , BucketAggregation(..)
345+ , TermsAggregation(..)
346+ , MissingAggregation(..)
347+ , ValueCountAggregation(..)
348+ , FilterAggregation(..)
349+ , CardinalityAggregation(..)
350+ , DateHistogramAggregation(..)
351+ , DateRangeAggregation(..)
352+ , DateRangeAggRange(..)
354+ , DateMathAnchor(..)
355+ , DateMathModifier(..)
357+ , TopHitsAggregation(..)
360+ , FieldHighlight(..)
361+ , HighlightSettings(..)
362+ , PlainHighlight(..)
363+ , PostingsHighlight(..)
364+ , FastVectorHighlight(..)
365+ , CommonHighlight(..)
367+ , HighlightEncoder(..)
373+ , DateHistogramResult(..)
374+ , DateRangeResult(..)
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 (..),
387+import Control.Monad.State (MonadState)
388+import Control.Monad.Writer (MonadWriter)
390+import Data.Aeson.Types (Pair, Parser,
392+ parseEither, parseMaybe,
394+import qualified Data.ByteString.Lazy.Char8 as L
396+import Data.Hashable (Hashable)
397+import qualified Data.HashMap.Strict as HM
398+import Data.List (foldl', intercalate,
400+import Data.List.NonEmpty (NonEmpty (..), toList)
401+import qualified Data.Map.Strict as M
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,
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
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
422+import Database.V1.Bloodhound.Types.Class
423+import Database.V1.Bloodhound.Types.Internal
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)
434+-- defaultIndexSettings is exported by Database.Bloodhound as well
435+-- no trailing slashes in servers, library handles building the path.
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.:
440+-- >> (mkBHEnv myServer myManager) { bhRequestHook = customHook }
441+mkBHEnv :: Server -> Manager -> BHEnv
442+mkBHEnv s m = BHEnv s m return
444+newtype BH m a = BH {
445+ unBH :: ReaderT BHEnv m a
446+ } deriving ( Functor
460+instance MonadTrans BH where
463+instance (MonadReader r m) => MonadReader r (BH m) where
465+ local f (BH (ReaderT m)) = BH $ ReaderT $ \r ->
468+instance (Functor m, Applicative m, MonadIO m) => MonadBH (BH m) where
469+ getBHEnv = BH getBHEnv
471+runBH :: BHEnv -> BH m a -> m a
472+runBH e f = runReaderT (unBH f) e
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)
481+-- | Traditional software versioning number
482+newtype VersionNumber = VersionNumber { versionNumber :: Vers.Version
483+ } deriving (Eq, Read, Show, Generic, Typeable, Ord)
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.
488+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-status.html#indices-status>
491+data Status = Status { ok :: Maybe Bool
494+ , version :: Version
495+ , tagline :: Text } deriving (Eq, Read, Show, Generic)
497+{-| 'IndexSettings' is used to configure the shards and replicas when you create
498+ an Elasticsearch Index.
500+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html>
504+ IndexSettings { indexShards :: ShardCount
505+ , indexReplicas :: ReplicaCount } deriving (Eq, Read, Show, Generic, Typeable)
507+{-| 'defaultIndexSettings' is an 'IndexSettings' with 3 shards and 2 replicas. -}
508+defaultIndexSettings :: IndexSettings
509+defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
512+{-| 'IndexOptimizationSettings' is used to configure index optimization. See
513+ <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-optimize.html>
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)
526+{-| 'defaultIndexOptimizationSettings' implements the default settings that
527+ ElasticSearch uses for index optimization. 'maxNumSegments' is Nothing,
528+ 'onlyExpungeDeletes' is False, and flushAfterOptimize is True.
530+defaultIndexOptimizationSettings :: IndexOptimizationSettings
531+defaultIndexOptimizationSettings = IndexOptimizationSettings Nothing False True
533+{-| 'UpdatableIndexSetting' are settings which may be updated after an index is created.
535+ <https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html>
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.
543+ -- ^ Set to True to disable read operations against the index.
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)
587+data AllocationPolicy = AllocAll
588+ -- ^ Allows shard allocation for all shards.
590+ -- ^ Allows shard allocation only for primary shards.
592+ -- ^ Allows shard allocation only for primary shards for new indices.
594+ -- ^ No shard allocation is allowed
595+ deriving (Eq, Read, Show, Generic, Typeable)
597+data ReplicaBounds = ReplicasBounded Int Int
598+ | ReplicasLowerBounded Int
600+ deriving (Eq, Read, Show, Generic, Typeable)
602+-- | A measure of bytes used for various configurations. You may want
603+-- to use smart constructors like 'gigabytes' for larger values.
613+newtype Bytes = Bytes Int deriving (Eq, Read, Show, Generic, Typeable, Ord, ToJSON, FromJSON)
615+gigabytes :: Int -> Bytes
616+gigabytes n = megabytes (1000 * n)
619+megabytes :: Int -> Bytes
620+megabytes n = kilobytes (1000 * n)
623+kilobytes :: Int -> Bytes
624+kilobytes n = Bytes (1000 * n)
627+data FSType = FSSimple
628+ | FSBuffered deriving (Eq, Read, Show, Generic, Typeable, Ord)
630+data InitialShardCount = QuorumShards
631+ | QuorumMinus1Shards
634+ | ExplicitShards Int
635+ deriving (Eq, Read, Show, Generic, Typeable)
637+data NodeAttrFilter = NodeAttrFilter { nodeAttrFilterName :: NodeAttrName
638+ , nodeAttrFilterValues :: NonEmpty Text}
639+ deriving (Eq, Read, Show, Generic, Ord, Typeable)
641+newtype NodeAttrName = NodeAttrName Text deriving (Eq, Read, Show, Ord, Generic, Typeable)
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)
648+newtype NominalDiffTimeJSON = NominalDiffTimeJSON { ndtJSON :: NominalDiffTime }
650+data IndexSettingsSummary = IndexSettingsSummary { sSummaryIndexName :: IndexName
651+ , sSummaryFixedSettings :: IndexSettings
652+ , sSummaryUpdateable :: [UpdatableIndexSetting]}
653+ deriving (Eq, Show, Generic, Typeable)
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
659+{-| 'OpenCloseIndex' is a sum type for opening and closing indices.
661+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html>
663+data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Read, Show, Generic, Typeable)
665+data FieldType = GeoPointType
671+ | ByteType deriving (Eq, Read, Show, Generic, Typeable)
673+data FieldDefinition =
674+ FieldDefinition { fieldType :: FieldType } deriving (Eq, Read, Show, Generic, Typeable)
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, ...]@
682+ https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
685+ IndexTemplate { templatePattern :: TemplatePattern
686+ , templateSettings :: Maybe IndexSettings
687+ , templateMappings :: [Value]
691+ MappingField { mappingFieldName :: FieldName
692+ , fieldDefinition :: FieldDefinition } deriving (Eq, Read, Show, Generic, Typeable)
694+{-| Support for type reification of 'Mapping's is currently incomplete, for
695+ now the mapping API verbiage expects a 'ToJSON'able blob.
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.
701+data Mapping = Mapping { typeName :: TypeName
702+ , mappingFields :: [MappingField] } deriving (Eq, Read, Show, Generic, Typeable)
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.
708+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk>
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)
716+{-| 'EsResult' describes the standard wrapper JSON document that you see in
717+ successful Elasticsearch lookups or lookups that couldn't find the document.
719+data EsResult a = EsResult { _index :: Text
722+ , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Read, Show, Generic, Typeable)
724+{-| 'EsResultFound' contains the document and its metadata inside of an
725+ 'EsResult' when the document was successfully found.
727+data EsResultFound a = EsResultFound { _version :: DocVersion
728+ , _source :: a } deriving (Eq, Read, Show, Generic, Typeable)
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
734+data EsError = EsError { errorStatus :: Int
735+ , errorMessage :: Text } deriving (Eq, Read, Show, Generic, Typeable)
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.
745+data EsProtocolException = EsProtocolException { esProtoExBody :: L.ByteString }
746+ deriving (Eq, Read, Show, Generic, Typeable)
748+instance Exception EsProtocolException
750+data IndexAlias = IndexAlias { srcIndex :: IndexName
751+ , indexAlias :: IndexAliasName } deriving (Eq, Read, Show, Generic, Typeable)
753+newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Read, Show, Generic, ToJSON)
755+data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
756+ | RemoveAlias IndexAlias deriving (Read, Show, Eq, Generic, Typeable)
758+data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
759+ , aliasCreateFilter :: Maybe Filter}
760+ deriving (Read, Show, Eq, Generic, Typeable)
762+data AliasRouting = AllAliasRouting RoutingValue
763+ | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
764+ deriving (Read, Show, Eq, Generic, Typeable)
766+newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Read, Show, Eq, Generic, Typeable)
768+newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
770+newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
772+newtype IndexAliasesSummary = IndexAliasesSummary { indexAliasesSummary :: [IndexAliasSummary] } deriving (Read, Show, Eq, Generic, Typeable)
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)
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>>.
781+newtype DocVersion = DocVersion {
782+ docVersionNumber :: Int
783+ } deriving (Eq, Read, Show, Generic, Ord, ToJSON)
785+-- | Smart constructor for in-range doc version
786+mkDocVersion :: Int -> Maybe DocVersion
788+ | i >= (docVersionNumber minBound) && i <= (docVersionNumber maxBound) =
790+ | otherwise = Nothing
793+{-| 'ExternalDocVersion' is a convenience wrapper if your code uses its
794+own version numbers instead of ones from ES.
796+newtype ExternalDocVersion = ExternalDocVersion DocVersion
797+ deriving (Eq, Read, Show, Generic, Ord, Bounded, Enum, ToJSON)
799+{-| 'VersionControl' is specified when indexing documents as a
800+optimistic concurrency control.
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
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)
833+{-| 'DocumentParent' is used to specify a parent document.
835+newtype DocumentParent = DocumentParent DocId
836+ deriving (Eq, Read, Show, Generic, Typeable)
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'
842+data IndexDocumentSettings =
843+ IndexDocumentSettings { idsVersionControl :: VersionControl
844+ , idsParent :: Maybe DocumentParent
845+ } deriving (Eq, Read, Show, Generic, Typeable)
847+{-| Reasonable default settings. Chooses no version control and no parent.
849+defaultIndexDocumentSettings :: IndexDocumentSettings
850+defaultIndexDocumentSettings = IndexDocumentSettings NoVersionControl Nothing
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.
855+type Sort = [SortSpec]
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
862+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
864+data SortSpec = DefaultSortSpec DefaultSort
865+ | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Read, Show, Generic, Typeable)
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
871+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
874+ DefaultSort { sortFieldName :: FieldName
875+ , sortOrder :: SortOrder
877+ , ignoreUnmapped :: Bool
878+ , sortMode :: Maybe SortMode
879+ , missingSort :: Maybe Missing
880+ , nestedFilter :: Maybe Filter } deriving (Eq, Read, Show, Generic, Typeable)
882+{-| 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get
883+ encoded into "asc" or "desc" when turned into JSON.
885+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
887+data SortOrder = Ascending
888+ | Descending deriving (Eq, Read, Show, Generic, Typeable)
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.
893+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_missing_values>
895+data Missing = LastMissing
897+ | CustomMissing Text deriving (Eq, Read, Show, Generic, Typeable)
899+{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
901+http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
903+data SortMode = SortMin
906+ | SortAvg deriving (Eq, Read, Show, Generic, Typeable)
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.
911+mkSort :: FieldName -> SortOrder -> DefaultSort
912+mkSort fieldName sOrder = DefaultSort fieldName sOrder False Nothing Nothing Nothing
914+{-| 'Cache' is for telling ES whether it should cache a 'Filter' not.
915+ 'Query's cannot be cached.
917+type Cache = Bool -- caching on/off
918+defaultCache :: Cache
921+{-| 'PrefixValue' is used in 'PrefixQuery' as the main query component.
923+type PrefixValue = Text
925+{-| 'BooleanOperator' is the usual And/Or operators with an ES compatible
926+ JSON encoding baked in. Used all over the place.
928+data BooleanOperator = And | Or deriving (Eq, Read, Show, Generic, Typeable)
930+{-| 'ShardCount' is part of 'IndexSettings'
932+newtype ShardCount = ShardCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
934+{-| 'ReplicaCount' is part of 'IndexSettings'
936+newtype ReplicaCount = ReplicaCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
938+{-| 'IndexName' is used to describe which index to query/create/delete
940+newtype IndexName = IndexName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
942+{-| 'IndexSelection' is used for APIs which take a single index, a list of
943+ indexes, or the special @_all@ index.
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)
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.
951+data NodeSelection = LocalNode
952+ -- ^ Whatever node receives this request
953+ | NodeList (NonEmpty NodeSelector)
954+ | AllNodes deriving (Eq, Generic, Show, Typeable)
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
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)
968+{-| 'TemplateName' is used to describe which template to query/create/delete
970+newtype TemplateName = TemplateName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
972+{-| 'TemplatePattern' represents a pattern which is matched against index names
974+newtype TemplatePattern = TemplatePattern Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
976+{-| 'MappingName' is part of mappings which are how ES describes and schematizes
977+ the data in the indices.
979+newtype MappingName = MappingName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
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.
985+newtype DocId = DocId Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
987+{-| 'QueryString' is used to wrap query text bodies, be they human written or not.
989+newtype QueryString = QueryString Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
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.
994+newtype FieldName = FieldName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
997+{-| 'Script' is often used in place of 'FieldName' to specify more
998+complex ways of extracting a value from a document.
1000+newtype Script = Script { scriptText :: Text } deriving (Eq, Read, Show, Generic, Typeable)
1002+{-| 'CacheName' is used in 'RegexpFilter' for describing the
1003+ 'CacheKey' keyed caching behavior.
1005+newtype CacheName = CacheName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1007+{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
1010+ CacheKey Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1012+ Existence Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
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)
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)
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.
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)
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)
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.
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)
1050+ Fuzziness Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
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)
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)
1060+ StopWord Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1062+ QueryPath Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
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)
1075+{-| By default, wildcard terms in a query are not analyzed.
1076+ Setting 'AnalyzeWildcard' to true enables best-effort analysis.
1078+newtype AnalyzeWildcard = AnalyzeWildcard Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1080+{-| 'GeneratePhraseQueries' defaults to false.
1082+newtype GeneratePhraseQueries =
1083+ GeneratePhraseQueries Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
1085+{-| 'Locale' is used for string conversions - defaults to ROOT.
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)
1091+{-| 'PhraseSlop' sets the default slop for phrases, 0 means exact
1092+ phrase matches. Default is 0.
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)
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 }
1101+{-| 'unpackId' is a silly convenience function that gets used once.
1103+unpackId :: DocId -> Text
1104+unpackId (DocId docId) = docId
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)
1110+data Search = Search { queryBody :: Maybe Query
1111+ , filterBody :: Maybe Filter
1112+ , sortBody :: Maybe Sort
1113+ , aggBody :: Maybe Aggregations
1114+ , highlight :: Maybe Highlights
1116+ , trackSortScores :: TrackSortScores
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)
1125+data SearchType = SearchTypeQueryThenFetch
1126+ | SearchTypeDfsQueryThenFetch
1129+ | SearchTypeQueryAndFetch
1130+ | SearchTypeDfsQueryAndFetch
1131+ deriving (Eq, Read, Show, Generic, Typeable)
1135+ | SourcePatterns PatternOrPatterns
1136+ | SourceIncludeExclude Include Exclude
1137+ deriving (Read, Show, Eq, Generic, Typeable)
1139+data PatternOrPatterns =
1141+ | PopPatterns [Pattern]
1142+ deriving (Eq, Read, Show, Generic, Typeable)
1144+data Include = Include [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
1145+data Exclude = Exclude [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
1147+newtype Pattern = Pattern Text deriving (Eq, Read, Show, Generic, Typeable)
1149+data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
1150+ , highlightFields :: [FieldHighlight]
1151+ } deriving (Read, Show, Eq, Generic, Typeable)
1153+data FieldHighlight = FieldHighlight FieldName (Maybe HighlightSettings)
1154+ deriving (Read, Show, Eq, Generic, Typeable)
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)
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)
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)
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)
1189+-- Settings that are only applicable to FastVector and Plain highlighters.
1191+ NonPostings { fragmentSize :: Maybe Int
1192+ , numberOfFragments :: Maybe Int} deriving (Read, Show, Eq, Generic, Typeable)
1194+data HighlightEncoder = DefaultEncoder
1196+ deriving (Read, Show, Eq, Generic, Typeable)
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)
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)
1236+ RegexpQuery { regexpQueryField :: FieldName
1237+ , regexpQuery :: Regexp
1238+ , regexpQueryFlags :: RegexpFlags
1239+ , regexpQueryBoost :: Maybe Boost
1240+ } deriving (Eq, Read, Show, Generic, Typeable)
1243+ RangeQuery { rangeQueryField :: FieldName
1244+ , rangeQueryRange :: RangeValue
1245+ , rangeQueryBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
1247+mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
1248+mkRangeQuery f r = RangeQuery f r (Boost 1.0)
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)
1261+data SimpleQueryFlag =
1266+ | SimpleQueryPrefix
1267+ | SimpleQueryPhrase
1268+ | SimpleQueryPrecedence
1269+ | SimpleQueryEscape
1270+ | SimpleQueryWhitespace
1273+ | SimpleQuerySlop deriving (Eq, Read, Show, Generic, Typeable)
1275+-- use_dis_max and tie_breaker when fields are plural?
1276+data 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)
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
1305+data FieldOrFields = FofField FieldName
1306+ | FofFields (NonEmpty FieldName) deriving (Eq, Read, Show, Generic, Typeable)
1310+ { prefixQueryField :: FieldName
1311+ , prefixQueryPrefixValue :: Text
1312+ , prefixQueryBoost :: Maybe Boost } deriving (Eq, Read, Show, Generic, Typeable)
1316+ { nestedQueryPath :: QueryPath
1317+ , nestedQueryScoreType :: ScoreType
1318+ , nestedQuery :: Query } deriving (Eq, Read, Show, Generic, Typeable)
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)
1338+data 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)
1358+ { indicesQueryIndices :: [IndexName]
1359+ , indicesQuery :: Query
1361+ , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Read, Show, Generic, Typeable)
1363+data HasParentQuery =
1365+ { hasParentQueryType :: TypeName
1366+ , hasParentQuery :: Query
1367+ , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1369+data HasChildQuery =
1371+ { hasChildQueryType :: TypeName
1372+ , hasChildQuery :: Query
1373+ , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1379+ | ScoreTypeNone deriving (Eq, Read, Show, Generic, Typeable)
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)
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)
1403+data 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)
1415+data FilteredQuery =
1417+ { filteredQuery :: Query
1418+ , filteredFilter :: Filter } deriving (Eq, Read, Show, Generic, Typeable)
1421+ DisMaxQuery { disMaxQueries :: [Query]
1423+ , disMaxTiebreaker :: Tiebreaker
1424+ , disMaxBoost :: Maybe Boost
1425+ } deriving (Eq, Read, Show, Generic, Typeable)
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)
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'
1442+mkMatchQuery :: FieldName -> QueryString -> MatchQuery
1443+mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1445+data MatchQueryType =
1447+ | MatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
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)
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'.
1466+mkMultiMatchQuery :: [FieldName] -> QueryString -> MultiMatchQuery
1467+mkMultiMatchQuery matchFields query =
1468+ MultiMatchQuery matchFields query
1469+ Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1471+data MultiMatchQueryType =
1472+ MultiMatchBestFields
1473+ | MultiMatchMostFields
1474+ | MultiMatchCrossFields
1476+ | MultiMatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
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)
1487+mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
1488+mkBoolQuery must mustNot should =
1489+ BoolQuery must mustNot should Nothing Nothing Nothing
1491+data BoostingQuery =
1492+ BoostingQuery { positiveQuery :: Query
1493+ , negativeQuery :: Query
1494+ , negativeBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
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)
1508+data CommonMinimumMatch =
1509+ CommonMinimumMatchHighLow MinimumMatchHighLow
1510+ | CommonMinimumMatch MinimumMatch
1511+ deriving (Eq, Read, Show, Generic, Typeable)
1513+data MinimumMatchHighLow =
1514+ MinimumMatchHighLow { lowFreq :: MinimumMatch
1515+ , highFreq :: MinimumMatch } deriving (Eq, Read, Show, Generic, Typeable)
1517+data Filter = AndFilter [Filter] Cache
1518+ | OrFilter [Filter] Cache
1519+ | NotFilter Filter Cache
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]
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)
1537+data ZeroTermsQuery = ZeroTermsNone
1538+ | ZeroTermsAll deriving (Eq, Read, Show, Generic, Typeable)
1540+data RangeExecution = RangeExecutionIndex
1541+ | RangeExecutionFielddata deriving (Eq, Read, Show, Generic, Typeable)
1543+newtype Regexp = Regexp Text deriving (Eq, Read, Show, Generic, Typeable, FromJSON)
1545+data RegexpFlags = AllRegexpFlags
1547+ | SomeRegexpFlags (NonEmpty RegexpFlag) deriving (Eq, Read, Show, Generic, Typeable)
1549+data RegexpFlag = AnyString
1554+ | Interval deriving (Eq, Read, Show, Generic, Typeable)
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)
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)
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)
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]
1603+data Term = Term { termField :: Text
1604+ , termValue :: Text } deriving (Eq, Read, Show, Generic, Typeable)
1606+data BoolMatch = MustMatch Term Cache
1607+ | MustNotMatch Term Cache
1608+ | ShouldMatch [Term] Cache deriving (Eq, Read, Show, Generic, Typeable)
1610+-- "memory" or "indexed"
1611+data GeoFilterType = GeoFilterMemory
1612+ | GeoFilterIndexed deriving (Eq, Read, Show, Generic, Typeable)
1614+data LatLon = LatLon { lat :: Double
1615+ , lon :: Double } deriving (Eq, Read, Show, Generic, Typeable)
1617+data GeoBoundingBox =
1618+ GeoBoundingBox { topLeft :: LatLon
1619+ , bottomRight :: LatLon } deriving (Eq, Read, Show, Generic, Typeable)
1621+data GeoBoundingBoxConstraint =
1622+ GeoBoundingBoxConstraint { geoBBField :: FieldName
1623+ , constraintBox :: GeoBoundingBox
1624+ , bbConstraintcache :: Cache
1625+ , geoType :: GeoFilterType
1626+ } deriving (Eq, Read, Show, Generic, Typeable)
1629+ GeoPoint { geoField :: FieldName
1630+ , latLon :: LatLon} deriving (Eq, Read, Show, Generic, Typeable)
1632+data DistanceUnit = Miles
1640+ | NauticalMiles deriving (Eq, Read, Show, Generic, Typeable)
1642+data DistanceType = Arc
1643+ | SloppyArc -- doesn't exist <1.0
1644+ | Plane deriving (Eq, Read, Show, Generic, Typeable)
1646+data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
1647+ | NoOptimizeBbox deriving (Eq, Read, Show, Generic, Typeable)
1650+ Distance { coefficient :: Double
1651+ , unit :: DistanceUnit } deriving (Eq, Read, Show, Generic, Typeable)
1653+data DistanceRange =
1654+ DistanceRange { distanceFrom :: Distance
1655+ , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
1657+type TemplateQueryKey = Text
1658+type TemplateQueryValue = Text
1660+newtype TemplateQueryKeyValuePairs = TemplateQueryKeyValuePairs (HM.HashMap TemplateQueryKey TemplateQueryValue)
1661+ deriving (Eq, Read, Show, Generic, Typeable)
1663+instance ToJSON TemplateQueryKeyValuePairs where
1664+ toJSON (TemplateQueryKeyValuePairs x) = Object $ HM.map toJSON x
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"
1672+data TemplateQueryInline =
1673+ TemplateQueryInline { inline :: Query
1674+ , params :: TemplateQueryKeyValuePairs
1676+ deriving (Eq, Read, Show, Generic, Typeable)
1678+instance ToJSON TemplateQueryInline where
1679+ toJSON TemplateQueryInline{..} = object [ "query" .= inline
1680+ , "params" .= params
1683+instance FromJSON TemplateQueryInline where
1684+ parseJSON = withObject "TemplateQueryInline" parse
1685+ where parse o = TemplateQueryInline
1689+data SearchResult a =
1690+ SearchResult { took :: Int
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.
1698+ deriving (Eq, Read, Show, Generic, Typeable)
1700+newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
1702+type Score = Maybe Double
1705+ SearchHits { hitsTotal :: Int
1706+ , maxScore :: Score
1707+ , hits :: [Hit a] } deriving (Eq, Read, Show, Generic, Typeable)
1709+instance Semigroup (SearchHits a) where
1710+ (SearchHits ta ma ha) <> (SearchHits tb mb hb) = SearchHits (ta + tb) (max ma mb) (ha <> hb)
1712+instance Monoid (SearchHits a) where
1713+ mempty = SearchHits 0 Nothing mempty
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)
1725+ ShardResult { shardTotal :: Int
1726+ , shardsSuccessful :: Int
1727+ , shardsFailed :: Int } deriving (Eq, Read, Show, Generic, Typeable)
1729+type HitHighlight = M.Map Text [Text]
1731+showText :: Show a => a -> Text
1732+showText = T.pack . show
1734+readMay :: Read a => String -> Maybe a
1735+readMay s = case reads s of
1736+ (a, ""):_ -> Just a
1739+parseReadText :: Read a => Text -> Parser a
1740+parseReadText = maybe mzero return . readMay . T.unpack
1742+type Aggregations = M.Map Text Aggregation
1744+emptyAggregations :: Aggregations
1745+emptyAggregations = M.empty
1747+mkAggregations :: Text -> Aggregation -> Aggregations
1748+mkAggregations name aggregation = M.insert name aggregation emptyAggregations
1750+data TermOrder = TermOrder{ termSortField :: Text
1751+ , termSortOrder :: SortOrder } deriving (Eq, Read, Show, Generic, Typeable)
1753+data TermInclusion = TermInclusion Text
1754+ | TermPattern Text Text deriving (Eq, Read, Show, Generic, Typeable)
1756+data CollectionMode = BreadthFirst
1757+ | DepthFirst deriving (Eq, Read, Show, Generic, Typeable)
1759+data ExecutionHint = Ordinals
1761+ | GlobalOrdinalsHash
1762+ | GlobalOrdinalsLowCardinality
1763+ | Map deriving (Eq, Read, Show, Generic, Typeable)
1765+data TimeInterval = Weeks
1769+ | Seconds deriving Eq
1771+data Interval = Year
1779+ | FractionalInterval Float TimeInterval deriving (Eq, Read, Show, Generic, Typeable)
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)
1791+data TopHitsAggregation = TopHitsAggregation
1792+ { taFrom :: Maybe From
1793+ , taSize :: Maybe Size
1794+ , taSort :: Maybe Sort
1795+ } deriving (Eq, Read, Show)
1797+data MissingAggregation = MissingAggregation
1799+ } deriving (Eq, Read, Show, Generic, Typeable)
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)
1813+data CardinalityAggregation = CardinalityAggregation { cardinalityField :: FieldName,
1814+ precisionThreshold :: Maybe Int
1815+ } deriving (Eq, Read, Show, Generic, Typeable)
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)
1829+data DateRangeAggregation = DateRangeAggregation { draField :: FieldName
1830+ , draFormat :: Maybe Text
1831+ , draRanges :: NonEmpty DateRangeAggRange
1832+ } deriving (Eq, Read, Show, Generic, Typeable)
1834+data DateRangeAggRange = DateRangeFrom DateMathExpr
1835+ | DateRangeTo DateMathExpr
1836+ | DateRangeFromAndTo DateMathExpr DateMathExpr deriving (Eq, Read, Show, Generic, Typeable)
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)
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)
1846+data DateMathModifier = AddTime Int DateMathUnit
1847+ | SubtractTime Int DateMathUnit
1848+ | RoundDownTo DateMathUnit deriving (Eq, Read, Show, Generic, Typeable)
1850+data DateMathUnit = DMYear
1856+ | DMSecond deriving (Eq, Read, Show, Generic, Typeable)
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)
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)
1866+mkTermsAggregation :: Text -> TermsAggregation
1867+mkTermsAggregation t = TermsAggregation (Left t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1869+mkTermsScriptAggregation :: Text -> TermsAggregation
1870+mkTermsScriptAggregation t = TermsAggregation (Right t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1872+mkDateHistogram :: FieldName -> Interval -> DateHistogramAggregation
1873+mkDateHistogram t i = DateHistogramAggregation t i Nothing Nothing Nothing Nothing Nothing Nothing
1875+mkCardinalityAggregation :: FieldName -> CardinalityAggregation
1876+mkCardinalityAggregation t = CardinalityAggregation t Nothing
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]
1885+instance FromJSON Version where
1886+ parseJSON = withObject "Version" parse
1887+ where parse o = Version
1889+ <*> o .: "build_hash"
1890+ <*> o .: "build_timestamp"
1891+ <*> o .: "build_snapshot"
1892+ <*> o .: "lucene_version"
1894+instance ToJSON VersionNumber where
1895+ toJSON = toJSON . Vers.showVersion . versionNumber
1897+instance FromJSON VersionNumber where
1898+ parseJSON = withText "VersionNumber" (parse . T.unpack)
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) ++ ")")
1905+instance ToJSON TermOrder where
1906+ toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
1908+instance ToJSON TermInclusion where
1909+ toJSON (TermInclusion x) = toJSON x
1910+ toJSON (TermPattern pattern flags) =
1911+ omitNulls [ "pattern" .= pattern
1912+ , "flags" .= flags]
1914+instance ToJSON CollectionMode where
1915+ toJSON BreadthFirst = "breadth_first"
1916+ toJSON DepthFirst = "depth_first"
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"
1925+instance ToJSON Interval where
1926+ toJSON Year = "year"
1927+ toJSON Quarter = "quarter"
1928+ toJSON Month = "month"
1929+ toJSON Week = "week"
1931+ toJSON Hour = "hour"
1932+ toJSON Minute = "minute"
1933+ toJSON Second = "second"
1934+ toJSON (FractionalInterval fraction interval) = toJSON $ show fraction ++ show interval
1936+instance Show TimeInterval where
1943+instance Read TimeInterval where
1944+ readPrec = f =<< TR.get
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"
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,
1959+ "min_doc_count" .= minDocCount,
1961+ "shard_size" .= shardSize,
1962+ "collect_mode" .= collectMode,
1963+ "execution_hint" .= executionHint
1965+ "aggs" .= termAggs ]
1967+ toJSON' x = case x of { Left y -> "field" .= y; Right y -> "script" .= y }
1969+ toJSON (CardinalityAgg (CardinalityAggregation field precisionThreshold)) =
1970+ object ["cardinality" .= omitNulls [ "field" .= field,
1971+ "precisionThreshold" .= precisionThreshold
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
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
1992+ toJSON (DateRangeAgg a) = object [ "date_range" .= a
1994+ toJSON (MissingAgg (MissingAggregation{..})) =
1995+ object ["missing" .= object ["field" .= maField]]
1997+ toJSON (TopHitsAgg (TopHitsAggregation mfrom msize msort)) =
1998+ omitNulls ["top_hits" .= omitNulls [ "size" .= msize
2004+instance ToJSON DateRangeAggregation where
2005+ toJSON DateRangeAggregation {..} =
2006+ omitNulls [ "field" .= draField
2007+ , "format" .= draFormat
2008+ , "ranges" .= toList draRanges
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 ]
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
2028+ fmtU DMMinute = "m"
2029+ fmtU DMSecond = "s"
2032+type AggregationResults = M.Map Text Value
2034+class BucketAggregation a where
2035+ key :: a -> BucketValue
2036+ docCount :: a -> Int
2037+ aggs :: a -> Maybe AggregationResults
2040+data Bucket a = Bucket { buckets :: [a]} deriving (Read, Show)
2042+data BucketValue = TextValue Text
2043+ | ScientificValue Scientific
2044+ | BoolValue Bool deriving (Read, Show)
2046+data MissingResult = MissingResult { missingDocCount :: Int } deriving (Show)
2048+data TopHitResult a = TopHitResult { tarHits :: (SearchHits a)
2051+data TermsResult = TermsResult { termKey :: BucketValue
2052+ , termsDocCount :: Int
2053+ , termsAggs :: Maybe AggregationResults } deriving (Read, Show)
2055+data DateHistogramResult = DateHistogramResult { dateKey :: Int
2056+ , dateKeyStr :: Maybe Text
2057+ , dateDocCount :: Int
2058+ , dateHistogramAggs :: Maybe AggregationResults } deriving (Read, Show)
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)
2068+toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
2069+toTerms = toAggResult
2071+toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
2072+toDateHistogram = toAggResult
2074+toMissing :: Text -> AggregationResults -> Maybe MissingResult
2075+toMissing = toAggResult
2077+toTopHits :: (FromJSON a) => Text -> AggregationResults -> Maybe (TopHitResult a)
2078+toTopHits = toAggResult
2080+toAggResult :: (FromJSON a) => Text -> AggregationResults -> Maybe a
2081+toAggResult t a = M.lookup t a >>= deserialize
2082+ where deserialize = parseMaybe parseJSON
2084+instance BucketAggregation TermsResult where
2086+ docCount = termsDocCount
2089+instance BucketAggregation DateHistogramResult where
2090+ key = TextValue . showText . dateKey
2091+ docCount = dateDocCount
2092+ aggs = dateHistogramAggs
2094+instance BucketAggregation DateRangeResult where
2095+ key = TextValue . dateRangeKey
2096+ docCount = dateRangeDocCount
2097+ aggs = dateRangeAggs
2099+instance (FromJSON a) => FromJSON (Bucket a) where
2100+ parseJSON (Object v) = Bucket <$>
2102+ parseJSON _ = mempty
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
2110+instance FromJSON MissingResult where
2111+ parseJSON = withObject "MissingResult" parse
2112+ where parse v = MissingResult <$> v .: "doc_count"
2114+instance FromJSON TermsResult where
2115+ parseJSON (Object v) = TermsResult <$>
2117+ v .: "doc_count" <*>
2118+ (pure $ getNamedSubAgg v ["key", "doc_count"])
2119+ parseJSON _ = mempty
2121+instance FromJSON DateHistogramResult where
2122+ parseJSON (Object v) = DateHistogramResult <$>
2124+ v .:? "key_as_string" <*>
2125+ v .: "doc_count" <*>
2126+ (pure $ getNamedSubAgg v [ "key"
2131+ parseJSON _ = mempty
2133+instance FromJSON DateRangeResult where
2134+ parseJSON = withObject "DateRangeResult" parse
2135+ where parse v = DateRangeResult <$>
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"
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)))
2156+instance (FromJSON a) => FromJSON (TopHitResult a) where
2157+ parseJSON (Object v) = TopHitResult <$>
2159+ parseJSON _ = fail "Failure in FromJSON (TopHitResult a)"
2161+instance Semigroup Filter where
2162+ a <> b = AndFilter [a, b] defaultCache
2164+instance Monoid Filter where
2165+ mempty = IdentityFilter
2168+instance Seminearring Filter where
2169+ a <||> b = OrFilter [a, b] defaultCache
2171+instance ToJSON Filter where
2172+ toJSON (AndFilter filters cache) =
2174+ object [ "filters" .= fmap toJSON filters
2175+ , "_cache" .= cache]]
2177+ toJSON (OrFilter filters cache) =
2179+ object [ "filters" .= fmap toJSON filters
2180+ , "_cache" .= cache]]
2182+ toJSON (NotFilter notFilter cache) =
2184+ object ["filter" .= notFilter
2185+ , "_cache" .= cache]]
2187+ toJSON (IdentityFilter) =
2188+ object ["match_all" .= object []]
2190+ toJSON (TermFilter (Term termFilterField termFilterValue) cache) =
2191+ object ["term" .= object base]
2192+ where base = [termFilterField .= termFilterValue,
2195+ toJSON (ExistsFilter (FieldName fieldName)) =
2196+ object ["exists" .= object
2197+ ["field" .= fieldName]]
2199+ toJSON (BoolFilter boolMatch) =
2200+ object ["bool" .= boolMatch]
2202+ toJSON (GeoBoundingBoxFilter bbConstraint) =
2203+ object ["geo_bounding_box" .= bbConstraint]
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]]
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]]
2221+ toJSON (GeoPolygonFilter (FieldName geoPolygonFilterField) latLons) =
2222+ object ["geo_polygon" .=
2223+ object [geoPolygonFilterField .=
2224+ object ["points" .= fmap toJSON latLons]]]
2226+ toJSON (IdsFilter (MappingName mappingName) values) =
2228+ object ["type" .= mappingName
2229+ , "values" .= fmap unpackId values]]
2231+ toJSON (LimitFilter limit) =
2232+ object ["limit" .= object ["value" .= limit]]
2234+ toJSON (MissingFilter (FieldName fieldName) (Existence existence) (NullValue nullValue)) =
2235+ object ["missing" .=
2236+ object [ "field" .= fieldName
2237+ , "existence" .= existence
2238+ , "null_value" .= nullValue]]
2240+ toJSON (PrefixFilter (FieldName fieldName) fieldValue cache) =
2241+ object ["prefix" .=
2242+ object [fieldName .= fieldValue
2243+ , "_cache" .= cache]]
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 ]]
2252+ toJSON (RangeFilter (FieldName fieldName) rangeValue rangeExecution cache) =
2254+ object [ fieldName .= object (rangeValueToPair rangeValue)
2255+ , "execution" .= rangeExecution
2256+ , "_cache" .= cache]]
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]]
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
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
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
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"
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"
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)
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)
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"
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"
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
2362+ | HM.null unknownKeys = Nothing
2363+ | otherwise = Just . M.fromList $ HM.toList unknownKeys
2365+instance ToJSON GeoPoint where
2366+ toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
2367+ object [ geoPointField .= geoPointLatLon ]
2370+instance ToJSON Query where
2371+ toJSON (TermQuery (Term termQueryField termQueryValue) boost) =
2373+ object [termQueryField .= object merged]]
2375+ base = [ "value" .= termQueryValue ]
2376+ boosted = maybe [] (return . ("boost" .=)) boost
2377+ merged = mappend base boosted
2379+ toJSON (TermsQuery fieldName terms) =
2380+ object [ "terms" .= object conjoined ]
2381+ where conjoined = [fieldName .= terms]
2383+ toJSON (IdsQuery idsQueryMappingName docIds) =
2384+ object [ "ids" .= object conjoined ]
2385+ where conjoined = [ "type" .= idsQueryMappingName
2386+ , "values" .= fmap toJSON docIds ]
2388+ toJSON (QueryQueryStringQuery qQueryStringQuery) =
2389+ object [ "query_string" .= qQueryStringQuery ]
2391+ toJSON (QueryMatchQuery matchQuery) =
2392+ object [ "match" .= matchQuery ]
2394+ toJSON (QueryMultiMatchQuery multiMatchQuery) =
2395+ toJSON multiMatchQuery
2397+ toJSON (QueryBoolQuery boolQuery) =
2398+ object [ "bool" .= boolQuery ]
2400+ toJSON (QueryBoostingQuery boostingQuery) =
2401+ object [ "boosting" .= boostingQuery ]
2403+ toJSON (QueryCommonTermsQuery commonTermsQuery) =
2404+ object [ "common" .= commonTermsQuery ]
2406+ toJSON (ConstantScoreFilter csFilter boost) =
2407+ object ["constant_score" .= object ["filter" .= csFilter
2408+ , "boost" .= boost]]
2410+ toJSON (ConstantScoreQuery query boost) =
2411+ object ["constant_score" .= object ["query" .= query
2412+ , "boost" .= boost]]
2414+ toJSON (QueryDisMaxQuery disMaxQuery) =
2415+ object [ "dis_max" .= disMaxQuery ]
2417+ toJSON (QueryFilteredQuery qFilteredQuery) =
2418+ object [ "filtered" .= qFilteredQuery ]
2420+ toJSON (QueryFuzzyLikeThisQuery fuzzyQuery) =
2421+ object [ "fuzzy_like_this" .= fuzzyQuery ]
2423+ toJSON (QueryFuzzyLikeFieldQuery fuzzyFieldQuery) =
2424+ object [ "fuzzy_like_this_field" .= fuzzyFieldQuery ]
2426+ toJSON (QueryFuzzyQuery fuzzyQuery) =
2427+ object [ "fuzzy" .= fuzzyQuery ]
2429+ toJSON (QueryHasChildQuery childQuery) =
2430+ object [ "has_child" .= childQuery ]
2432+ toJSON (QueryHasParentQuery parentQuery) =
2433+ object [ "has_parent" .= parentQuery ]
2435+ toJSON (QueryIndicesQuery qIndicesQuery) =
2436+ object [ "indices" .= qIndicesQuery ]
2438+ toJSON (MatchAllQuery boost) =
2439+ object [ "match_all" .= omitNulls [ "boost" .= boost ] ]
2441+ toJSON (QueryMoreLikeThisQuery query) =
2442+ object [ "more_like_this" .= query ]
2444+ toJSON (QueryMoreLikeThisFieldQuery query) =
2445+ object [ "more_like_this_field" .= query ]
2447+ toJSON (QueryNestedQuery query) =
2448+ object [ "nested" .= query ]
2450+ toJSON (QueryPrefixQuery query) =
2451+ object [ "prefix" .= query ]
2453+ toJSON (QueryRangeQuery query) =
2454+ object [ "range" .= query ]
2456+ toJSON (QueryRegexpQuery query) =
2457+ object [ "regexp" .= query ]
2459+ toJSON (QuerySimpleQueryStringQuery query) =
2460+ object [ "simple_query_string" .= query ]
2462+ toJSON (QueryTemplateQueryInline templateQuery) =
2463+ object [ "template" .= templateQuery ]
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
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"
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
2515+ _ -> fail "Does not appear to be a ConstantScoreFilter"
2516+ constantScoreQuery o = case HM.lookup "query" o of
2517+ Just x -> ConstantScoreQuery <$> parseJSON x
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
2539+omitNulls :: [(Text, Value)] -> Value
2540+omitNulls = object . filter notNull where
2541+ notNull (_, Null) = False
2542+ notNull (_, Array a) = (not . V.null) a
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 ]
2557+instance FromJSON SimpleQueryStringQuery where
2558+ parseJSON = withObject "SimpleQueryStringQuery" parse
2559+ where parse o = SimpleQueryStringQuery <$> o .: "query"
2561+ <*> o .:? "default_operator"
2562+ <*> o .:? "analyzer"
2563+ <*> (parseFlags <$> o .:? "flags")
2564+ <*> o .:? "lowercase_expanded_terms"
2566+ parseFlags (Just (x:xs)) = Just (x :| xs)
2567+ parseFlags _ = Nothing
2569+instance ToJSON FieldOrFields where
2570+ toJSON (FofField fieldName) =
2572+ toJSON (FofFields fieldNames) =
2575+instance FromJSON FieldOrFields where
2576+ parseJSON v = FofField <$> parseJSON v
2577+ <|> FofFields <$> (parseNEJSON =<< parseJSON v)
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"
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)
2609+instance ToJSON RegexpQuery where
2610+ toJSON (RegexpQuery (FieldName rqQueryField)
2611+ (Regexp regexpQueryQuery) rqQueryFlags
2613+ object [ rqQueryField .= omitNulls base ]
2614+ where base = [ "value" .= regexpQueryQuery
2615+ , "flags" .= rqQueryFlags
2616+ , "boost" .= rqQueryBoost ]
2618+instance FromJSON RegexpQuery where
2619+ parseJSON = withObject "RegexpQuery" parse
2620+ where parse = fieldTagged $ \fn o ->
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) =
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 ]
2656+instance FromJSON QueryStringQuery where
2657+ parseJSON = withObject "QueryStringQuery" parse
2658+ where parse o = QueryStringQuery
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"
2671+ <*> o .:? "analyze_wildcard"
2672+ <*> o .:? "auto_generate_phrase_queries"
2673+ <*> o .:? "minimum_should_match"
2674+ <*> o .:? "lenient"
2677+instance ToJSON RangeQuery where
2678+ toJSON (RangeQuery (FieldName fieldName) range boost) =
2679+ object [ fieldName .= object conjoined ]
2680+ where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
2682+instance FromJSON RangeQuery where
2683+ parseJSON = withObject "RangeQuery" parse
2684+ where parse = fieldTagged $ \fn o ->
2686+ <$> parseJSON (Object o)
2689+instance FromJSON RangeValue where
2690+ parseJSON = withObject "RangeValue" parse
2691+ where parse o = parseDate o
2693+ parseDate o = do lt <- o .:? "lt"
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"
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
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 ]
2728+instance FromJSON PrefixQuery where
2729+ parseJSON = withObject "PrefixQuery" parse
2730+ where parse = fieldTagged $ \fn o ->
2735+instance ToJSON NestedQuery where
2736+ toJSON (NestedQuery nqPath nqScoreType nqQuery) =
2737+ object [ "path" .= nqPath
2738+ , "score_mode" .= nqScoreType
2739+ , "query" .= nqQuery ]
2741+instance FromJSON NestedQuery where
2742+ parseJSON = withObject "NestedQuery" parse
2743+ where parse o = NestedQuery
2745+ <*> o .: "score_mode"
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
2764+ , "analyzer" .= analyzer ]
2766+instance FromJSON MoreLikeThisFieldQuery where
2767+ parseJSON = withObject "MoreLikeThisFieldQuery" parse
2768+ where parse = fieldTagged $ \fn o ->
2769+ MoreLikeThisFieldQuery
2770+ <$> o .: "like_text"
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"
2783+ <*> o .:? "analyzer"
2784+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2786+instance ToJSON MoreLikeThisQuery where
2787+ toJSON (MoreLikeThisQuery text fields percent
2788+ mtf mqt stopwords mindf maxdf
2789+ minwl maxwl boostTerms boost analyzer) =
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
2803+ , "analyzer" .= analyzer ]
2805+instance FromJSON MoreLikeThisQuery where
2806+ parseJSON = withObject "MoreLikeThisQuery" parse
2807+ where parse o = MoreLikeThisQuery
2808+ <$> o .: "like_text"
2809+ -- <*> (optionalNE =<< 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"
2822+ <*> o .:? "analyzer"
2823+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2825+instance ToJSON IndicesQuery where
2826+ toJSON (IndicesQuery indices query noMatch) =
2827+ omitNulls [ "indices" .= indices
2828+ , "no_match_query" .= noMatch
2829+ , "query" .= query ]
2831+instance FromJSON IndicesQuery where
2832+ parseJSON = withObject "IndicesQuery" parse
2833+ where parse o = IndicesQuery
2834+ <$> o .:? "indices" .!= []
2836+ <*> o .:? "no_match_query"
2838+instance ToJSON HasParentQuery where
2839+ toJSON (HasParentQuery queryType query scoreType) =
2840+ omitNulls [ "parent_type" .= queryType
2841+ , "score_type" .= scoreType
2842+ , "query" .= query ]
2844+instance FromJSON HasParentQuery where
2845+ parseJSON = withObject "HasParentQuery" parse
2846+ where parse o = HasParentQuery
2847+ <$> o .: "parent_type"
2849+ <*> o .:? "score_type"
2851+instance ToJSON HasChildQuery where
2852+ toJSON (HasChildQuery queryType query scoreType) =
2853+ omitNulls [ "query" .= query
2854+ , "score_type" .= scoreType
2855+ , "type" .= queryType ]
2857+instance FromJSON HasChildQuery where
2858+ parseJSON = withObject "HasChildQuery" parse
2859+ where parse o = HasChildQuery
2862+ <*> o .:? "score_type"
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
2872+ , "max_expansions" .= maxEx ]
2874+instance FromJSON FuzzyQuery where
2875+ parseJSON = withObject "FuzzyQuery" parse
2876+ where parse = fieldTagged $ \fn o ->
2879+ <*> o .: "prefix_length"
2880+ <*> o .: "max_expansions"
2881+ <*> o .: "fuzziness"
2884+instance ToJSON FuzzyLikeFieldQuery where
2885+ toJSON (FuzzyLikeFieldQuery (FieldName fieldName)
2886+ fieldText maxTerms ignoreFreq fuzziness prefixLength
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 ]]
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"
2907+ <*> o .:? "analyzer"
2909+instance ToJSON FuzzyLikeThisQuery where
2910+ toJSON (FuzzyLikeThisQuery fields text maxTerms
2911+ ignoreFreq fuzziness prefixLength boost analyzer) =
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 ]
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"
2932+ <*> o .:? "analyzer"
2934+instance ToJSON FilteredQuery where
2935+ toJSON (FilteredQuery query fFilter) =
2936+ object [ "query" .= query
2937+ , "filter" .= fFilter ]
2939+instance FromJSON FilteredQuery where
2940+ parseJSON = withObject "FilteredQuery" parse
2941+ where parse o = FilteredQuery
2945+instance ToJSON DisMaxQuery where
2946+ toJSON (DisMaxQuery queries tiebreaker boost) =
2948+ where base = [ "queries" .= queries
2950+ , "tie_breaker" .= tiebreaker ]
2952+instance FromJSON DisMaxQuery where
2953+ parseJSON = withObject "DisMaxQuery" parse
2954+ where parse o = DisMaxQuery
2955+ <$> o .:? "queries" .!= []
2956+ <*> o .: "tie_breaker"
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
2969+ , "analyzer" .= analyzer
2970+ , "disable_coord" .= disableCoord
2971+ , "high_freq_operator" .= hfo ]
2973+instance FromJSON CommonTermsQuery where
2974+ parseJSON = withObject "CommonTermsQuery" parse
2975+ where parse = fieldTagged $ \fn o ->
2976+ CommonTermsQuery fn
2978+ <*> o .: "cutoff_frequency"
2979+ <*> o .: "low_freq_operator"
2980+ <*> o .: "high_freq_operator"
2981+ <*> o .:? "minimum_should_match"
2983+ <*> o .:? "analyzer"
2984+ <*> o .:? "disable_coord"
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 ]
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")
3002+instance ToJSON BoostingQuery where
3003+ toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
3004+ object [ "positive" .= bqPositiveQuery
3005+ , "negative" .= bqNegativeQuery
3006+ , "negative_boost" .= bqNegativeBoost ]
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"
3015+instance ToJSON BoolQuery where
3016+ toJSON (BoolQuery mustM notM shouldM bqMin boost disableCoord) =
3018+ where base = [ "must" .= mustM
3019+ , "must_not" .= notM
3020+ , "should" .= shouldM
3021+ , "minimum_should_match" .= bqMin
3023+ , "disable_coord" .= disableCoord ]
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"
3033+ <*> o .:? "disable_coord"
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 ]
3051+instance FromJSON MatchQuery where
3052+ parseJSON = withObject "MatchQuery" parse
3053+ where parse = fieldTagged $ \fn o ->
3056+ <*> o .: "operator"
3057+ <*> o .: "zero_terms_query"
3058+ <*> o .:? "cutoff_frequency"
3060+ <*> o .:? "analyzer"
3061+ <*> o .:? "max_expansions"
3062+ <*> o .:? "lenient"
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
3071+ , "operator" .= boolOp
3072+ , "zero_terms_query" .= ztQ
3073+ , "tie_breaker" .= tb
3075+ , "cutoff_frequency" .= cf
3076+ , "analyzer" .= analyzer
3077+ , "max_expansions" .= maxEx
3078+ , "lenient" .= lenient ]
3080+instance FromJSON MultiMatchQuery where
3081+ parseJSON = withObject "MultiMatchQuery" parse
3082+ where parse raw = do o <- raw .: "multi_match"
3084+ <$> o .:? "fields" .!= []
3086+ <*> o .: "operator"
3087+ <*> o .: "zero_terms_query"
3088+ <*> o .:? "tie_breaker"
3090+ <*> o .:? "cutoff_frequency"
3091+ <*> o .:? "analyzer"
3092+ <*> o .:? "max_expansions"
3093+ <*> o .:? "lenient"
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"
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)
3111+instance ToJSON BooleanOperator where
3112+ toJSON And = String "and"
3113+ toJSON Or = String "or"
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)
3121+instance ToJSON ZeroTermsQuery where
3122+ toJSON ZeroTermsNone = String "none"
3123+ toJSON ZeroTermsAll = String "all"
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)
3131+instance ToJSON MatchQueryType where
3132+ toJSON MatchPhrase = "phrase"
3133+ toJSON MatchPhrasePrefix = "phrase_prefix"
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)
3141+instance FromJSON Status where
3142+ parseJSON (Object v) = Status <$>
3144+ (v .:? "status" .!= 200) <*>
3148+ parseJSON _ = empty
3151+instance ToJSON IndexSettings where
3152+ toJSON (IndexSettings s r) = object ["settings" .=
3154+ object ["number_of_shards" .= s, "number_of_replicas" .= r]
3158+instance FromJSON IndexSettings where
3159+ parseJSON = withObject "IndexSettings" parse
3160+ where parse o = do s <- o .: "settings"
3162+ IndexSettings <$> i .: "number_of_shards"
3163+ <*> i .: "number_of_replicas"
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
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
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)
3263+ <*> (fmap (filter (not . redundant)) . parseSettings =<< o' .: "settings")
3264+ _ -> fail "Expected single-key object with index name"
3265+ redundant (NumberOfReplicas _) = True
3266+ redundant _ = False
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
3278+unStringlyTypeJSON v = v
3281+parseSettings :: Object -> Parser [UpdatableIndexSetting]
3282+parseSettings o = do
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)
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]
3296+attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
3297+attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
3298+ | NodeAttrFilter (NodeAttrName n) vs <- toList fs]
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"
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
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"
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"
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)
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
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
3356+instance ToJSON FSType where
3357+ toJSON FSSimple = "simple"
3358+ toJSON FSBuffered = "buffered"
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)
3366+instance ToJSON CompoundFormat where
3367+ toJSON (CompoundFileFormat x) = Bool x
3368+ toJSON (MergeSegmentVsTotalIndex x) = toJSON x
3370+instance FromJSON CompoundFormat where
3371+ parseJSON v = CompoundFileFormat <$> parseJSON v
3372+ <|> MergeSegmentVsTotalIndex <$> parseJSON v
3374+instance ToJSON NominalDiffTimeJSON where
3375+ toJSON (NominalDiffTimeJSON t) = String (showText (round t :: Integer) <> "s")
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)"
3383+instance ToJSON IndexTemplate where
3384+ toJSON (IndexTemplate p s m) = merge
3385+ (object [ "template" .= p
3386+ , "mappings" .= foldl' merge (object []) m
3390+ merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2
3392+ merge _ _ = undefined
3394+instance (FromJSON a) => FromJSON (EsResult a) where
3395+ parseJSON jsonVal@(Object v) = do
3396+ found <- v .:? "found" .!= False
3398+ then parseJSON jsonVal
3399+ else return Nothing
3400+ EsResult <$> v .: "_index" <*>
3404+ parseJSON _ = empty
3406+instance (FromJSON a) => FromJSON (EsResultFound a) where
3407+ parseJSON (Object v) = EsResultFound <$>
3408+ v .: "_version" <*>
3410+ parseJSON _ = empty
3412+instance FromJSON EsError where
3413+ parseJSON (Object v) = EsError <$>
3415+ (v .: "error" <|> (v .: "error" >>= (.: "reason")))
3416+ parseJSON _ = empty
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
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
3435+instance ToJSON IndexAlias where
3436+ toJSON IndexAlias {..} = object ["index" .= srcIndex
3437+ , "alias" .= indexAlias
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
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]
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)
3462+instance FromJSON IndexAliasCreate where
3463+ parseJSON v = withObject "IndexAliasCreate" parse v
3464+ where parse o = IndexAliasCreate <$> optional (parseJSON v)
3467+instance ToJSON SearchAliasRouting where
3468+ toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
3470+instance FromJSON SearchAliasRouting where
3471+ parseJSON = withText "SearchAliasRouting" parse
3472+ where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
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
3479+ , "aggregations" .= searchAggs
3480+ , "highlight" .= highlight
3483+ , "track_scores" .= sTrackSortScores
3484+ , "fields" .= sFields
3485+ , "_source" .= sSource
3486+ , "suggest" .= sSuggest]
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 ]
3494+instance ToJSON PatternOrPatterns where
3495+ toJSON (PopPattern pattern) = toJSON pattern
3496+ toJSON (PopPatterns patterns) = toJSON patterns
3498+instance ToJSON Include where
3499+ toJSON (Include patterns) = toJSON patterns
3501+instance ToJSON Exclude where
3502+ toJSON (Exclude patterns) = toJSON patterns
3504+instance ToJSON Pattern where
3505+ toJSON (Pattern pattern) = toJSON pattern
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 ]
3514+instance ToJSON Highlights where
3515+ toJSON (Highlights global fields) =
3516+ omitNulls (("fields" .= fields)
3517+ : highlightSettingsPairs global)
3519+instance ToJSON HighlightSettings where
3520+ toJSON hs = omitNulls (highlightSettingsPairs (Just hs))
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)
3529+plainHighPairs :: Maybe PlainHighlight -> [Pair]
3530+plainHighPairs Nothing = []
3531+plainHighPairs (Just (PlainHighlight plCom plNonPost)) =
3532+ [ "type" .= String "plain"]
3533+ ++ commonHighlightPairs plCom
3534+ ++ nonPostingsToPairs plNonPost
3536+postHighPairs :: Maybe PostingsHighlight -> [Pair]
3537+postHighPairs Nothing = []
3538+postHighPairs (Just (PostingsHighlight pCom)) =
3539+ ("type" .= String "postings")
3540+ : commonHighlightPairs pCom
3542+fastVectorHighPairs :: Maybe FastVectorHighlight -> [Pair]
3543+fastVectorHighPairs Nothing = []
3544+fastVectorHighPairs (Just
3545+ (FastVectorHighlight fvCom fvNonPostSettings fvBoundChars
3546+ fvBoundMaxScan fvFragOff fvMatchedFields
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
3557+deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
3558+deleteSeveral ks hm = foldr HM.delete hm ks
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
3574+nonPostingsToPairs :: Maybe NonPostings -> [Pair]
3575+nonPostingsToPairs Nothing = []
3576+nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
3577+ [ "fragment_size" .= npFragSize
3578+ , "number_of_fragments" .= npNumOfFrags]
3580+parseNEJSON :: (FromJSON a) => [Value] -> Parser (NonEmpty a)
3581+parseNEJSON [] = fail "Expected non-empty list"
3582+parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
3585+instance ToJSON HighlightEncoder where
3586+ toJSON DefaultEncoder = String "default"
3587+ toJSON HTMLEncoder = String "html"
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 = []
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 ]
3606+ toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) =
3607+ object [ "unit" .= units
3608+ , field .= gdsLatLon
3609+ , "order" .= gdsSortOrder ]
3612+instance ToJSON SortOrder where
3613+ toJSON Ascending = String "asc"
3614+ toJSON Descending = String "desc"
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"
3624+instance ToJSON Missing where
3625+ toJSON LastMissing = String "_last"
3626+ toJSON FirstMissing = String "_first"
3627+ toJSON (CustomMissing txt) = String txt
3630+instance ToJSON ScoreType where
3631+ toJSON ScoreTypeMax = "max"
3632+ toJSON ScoreTypeAvg = "avg"
3633+ toJSON ScoreTypeSum = "sum"
3634+ toJSON ScoreTypeNone = "none"
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)
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
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))
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"
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)
3689+instance ToJSON DistanceType where
3690+ toJSON Arc = String "arc"
3691+ toJSON SloppyArc = String "sloppy_arc"
3692+ toJSON Plane = String "plane"
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)
3702+instance ToJSON OptimizeBbox where
3703+ toJSON NoOptimizeBbox = String "none"
3704+ toJSON (OptimizeGeoFilterType gft) = toJSON gft
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
3713+instance ToJSON GeoBoundingBoxConstraint where
3714+ toJSON (GeoBoundingBoxConstraint
3715+ (FieldName gbbcGeoBBField) gbbcConstraintBox cache type') =
3716+ object [gbbcGeoBBField .= gbbcConstraintBox
3717+ , "_cache" .= cache
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)
3725+ <*> o .:? "_cache" .!= defaultCache
3727+ _ -> fail "Could not find field name for GeoBoundingBoxConstraint"
3729+instance ToJSON GeoFilterType where
3730+ toJSON GeoFilterMemory = String "memory"
3731+ toJSON GeoFilterIndexed = String "indexed"
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)
3739+instance ToJSON GeoBoundingBox where
3740+ toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
3741+ object ["top_left" .= gbbTopLeft
3742+ , "bottom_right" .= gbbBottomRight]
3744+instance FromJSON GeoBoundingBox where
3745+ parseJSON = withObject "GeoBoundingBox" parse
3746+ where parse o = GeoBoundingBox
3747+ <$> o .: "top_left"
3748+ <*> o .: "bottom_right"
3750+instance ToJSON LatLon where
3751+ toJSON (LatLon lLat lLon) =
3752+ object ["lat" .= lLat
3755+instance FromJSON LatLon where
3756+ parseJSON = withObject "LatLon" parse
3757+ where parse o = LatLon <$> o .: "lat"
3760+-- index for smaller ranges, fielddata for longer ranges
3761+instance ToJSON RangeExecution where
3762+ toJSON RangeExecutionIndex = "index"
3763+ toJSON RangeExecutionFielddata = "fielddata"
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)
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"
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)
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)
3800+instance ToJSON Term where
3801+ toJSON (Term field value) = object ["term" .= object
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"
3811+instance ToJSON BoolMatch where
3812+ toJSON (MustMatch term cache) = object ["must" .= term,
3814+ toJSON (MustNotMatch term cache) = object ["must_not" .= term,
3816+ toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
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
3829+instance (FromJSON a) => FromJSON (SearchResult a) where
3830+ parseJSON (Object v) = SearchResult <$>
3832+ v .: "timed_out" <*>
3835+ v .:? "aggregations" <*>
3836+ v .:? "_scroll_id" <*>
3838+ parseJSON _ = empty
3840+instance (FromJSON a) => FromJSON (SearchHits a) where
3841+ parseJSON (Object v) = SearchHits <$>
3843+ v .: "max_score" <*>
3845+ parseJSON _ = empty
3847+instance (FromJSON a) => FromJSON (Hit a) where
3848+ parseJSON (Object v) = Hit <$>
3853+ v .:? "_source" <*>
3855+ parseJSON _ = empty
3857+instance FromJSON ShardResult where
3858+ parseJSON (Object v) = ShardResult <$>
3860+ v .: "successful" <*>
3862+ parseJSON _ = empty
3865+instance FromJSON DocVersion where
3868+ maybe (fail "DocVersion out of range") return $ mkDocVersion i
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)
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)
3883+instance Bounded DocVersion where
3884+ minBound = DocVersion 1
3885+ maxBound = DocVersion 9200000000000000000 -- 9.2e+18
3887+instance Enum DocVersion where
3889+ | x /= maxBound = DocVersion (succ $ docVersionNumber x)
3890+ | otherwise = succError "DocVersion"
3892+ | x /= minBound = DocVersion (pred $ docVersionNumber x)
3893+ | otherwise = predError "DocVersion"
3895+ fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
3896+ fromEnum = docVersionNumber
3897+ enumFrom = boundedEnumFrom
3898+ enumFromThen = boundedEnumFromThen
3900+-- | Username type used for HTTP Basic authentication. See 'basicAuthHook'.
3901+newtype EsUsername = EsUsername { esUsername :: Text } deriving (Read, Show, Eq)
3903+-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
3904+newtype EsPassword = EsPassword { esPassword :: Text } deriving (Read, Show, Eq)
3907+data SnapshotRepoSelection = SnapshotRepoList (NonEmpty SnapshotRepoPattern)
3908+ | AllSnapshotRepos deriving (Eq, Generic, Show, Typeable)
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
3915+ deriving (Eq, Generic, Show, Typeable)
3917+-- | The unique name of a snapshot repository.
3918+newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
3919+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
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
3928+data GenericSnapshotRepo = GenericSnapshotRepo {
3929+ gSnapshotRepoName :: SnapshotRepoName
3930+ , gSnapshotRepoType :: SnapshotRepoType
3931+ , gSnapshotRepoSettings :: GenericSnapshotRepoSettings
3932+ } deriving (Eq, Generic, Show, Typeable)
3935+instance SnapshotRepo GenericSnapshotRepo where
3936+ toGSnapshotRepo = id
3937+ fromGSnapshotRepo = Right
3940+newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
3941+ deriving (Eq, Ord, Generic, Show, Typeable, ToJSON, FromJSON)
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)
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
3956+-- | The result of running 'verifySnapshotRepo'.
3957+newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
3958+ deriving (Eq, Generic, Show, Typeable)
3961+instance FromJSON SnapshotVerification where
3962+ parseJSON = withObject "SnapshotVerification" parse
3966+ SnapshotVerification <$> mapM (uncurry parse') (HM.toList o2)
3967+ parse' rawFullId = withObject "SnapshotNodeVerification" $ \o ->
3968+ SnapshotNodeVerification (FullNodeId rawFullId) <$> o .: "name"
3971+-- | A node that has verified a snapshot
3972+data SnapshotNodeVerification = SnapshotNodeVerification {
3973+ snvFullId :: FullNodeId
3974+ , snvNodeName :: NodeName
3975+ } deriving (Eq, Generic, Show, Typeable)
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)
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)
3989+newtype ClusterName = ClusterName { clusterName :: Text }
3990+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
3992+data NodesInfo = NodesInfo {
3993+ nodesInfo :: [NodeInfo]
3994+ , nodesClusterName :: ClusterName
3995+ } deriving (Eq, Show, Generic, Typeable)
3997+data NodesStats = NodesStats {
3998+ nodesStats :: [NodeStats]
3999+ , nodesStatsClusterName :: ClusterName
4000+ } deriving (Eq, Show, Generic, Typeable)
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)
4017+data NodeBreakersStats = NodeBreakersStats {
4018+ nodeStatsParentBreaker :: NodeBreakerStats
4019+ , nodeStatsRequestBreaker :: NodeBreakerStats
4020+ , nodeStatsFieldDataBreaker :: NodeBreakerStats
4021+ } deriving (Eq, Show, Generic, Typeable)
4023+data NodeBreakerStats = NodeBreakerStats {
4024+ nodeBreakersTripped :: Int
4025+ , nodeBreakersOverhead :: Double
4026+ , nodeBreakersEstSize :: Bytes
4027+ , nodeBreakersLimitSize :: Bytes
4028+ } deriving (Eq, Show, Generic, Typeable)
4030+data NodeHTTPStats = NodeHTTPStats {
4031+ nodeHTTPTotalOpened :: Int
4032+ , nodeHTTPCurrentOpen :: Int
4033+ } deriving (Eq, Show, Generic, Typeable)
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)
4043+data NodeFSStats = NodeFSStats {
4044+ nodeFSDataPaths :: [NodeDataPathStats]
4045+ , nodeFSTotal :: NodeFSTotalStats
4046+ , nodeFSTimestamp :: UTCTime
4047+ } deriving (Eq, Show, Generic, Typeable)
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)
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)
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)
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)
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)
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)
4143+data JVMBufferPoolStats = JVMBufferPoolStats {
4144+ jvmBufferPoolStatsTotalCapacity :: Bytes
4145+ , jvmBufferPoolStatsUsed :: Bytes
4146+ , jvmBufferPoolStatsCount :: Int
4147+ } deriving (Eq, Show, Generic, Typeable)
4149+data JVMGCStats = JVMGCStats {
4150+ jvmGCStatsCollectionTime :: NominalDiffTime
4151+ , jvmGCStatsCollectionCount :: Int
4152+ } deriving (Eq, Show, Generic, Typeable)
4154+data JVMPoolStats = JVMPoolStats {
4155+ jvmPoolStatsPeakMax :: Bytes
4156+ , jvmPoolStatsPeakUsed :: Bytes
4157+ , jvmPoolStatsMax :: Bytes
4158+ , jvmPoolStatsUsed :: Bytes
4159+ } deriving (Eq, Show, Generic, Typeable)
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)
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)
4192+data LoadAvgs = LoadAvgs {
4193+ loadAvg1Min :: Double
4194+ , loadAvg5Min :: Double
4195+ , loadAvg15Min :: Double
4196+ } deriving (Eq, Show, Generic, Typeable)
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)
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)
4277+-- | Typically a 7 character hex string.
4278+newtype BuildHash = BuildHash { buildHash :: Text }
4279+ deriving (Eq, Ord, Generic, Read, Show, Typeable, FromJSON, ToJSON)
4281+newtype PluginName = PluginName { pluginName :: Text }
4282+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
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)
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)
4316+data NodeHTTPInfo = NodeHTTPInfo {
4317+ nodeHTTPMaxContentLength :: Bytes
4318+ , nodeHTTPTransportAddress :: BoundTransportAddress
4319+ } deriving (Eq, Show, Generic, Typeable)
4321+data NodeTransportInfo = NodeTransportInfo {
4322+ nodeTransportProfiles :: [BoundTransportAddress]
4323+ , nodeTransportAddress :: BoundTransportAddress
4324+ } deriving (Eq, Show, Generic, Typeable)
4326+data BoundTransportAddress = BoundTransportAddress {
4327+ publishAddress :: EsAddress
4328+ , boundAddress :: EsAddress
4329+ } deriving (Eq, Show, Generic, Typeable)
4331+data NodeNetworkInfo = NodeNetworkInfo {
4332+ nodeNetworkPrimaryInterface :: NodeNetworkInterface
4333+ , nodeNetworkRefreshInterval :: NominalDiffTime
4334+ } deriving (Eq, Show, Generic, Typeable)
4336+newtype MacAddress = MacAddress { macAddress :: Text }
4337+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4339+newtype NetworkInterfaceName = NetworkInterfaceName { networkInterfaceName :: Text }
4340+ deriving (Eq, Ord, Generic, Show, Typeable, FromJSON)
4342+data NodeNetworkInterface = NodeNetworkInterface {
4343+ nodeNetIfaceMacAddress :: MacAddress
4344+ , nodeNetIfaceName :: NetworkInterfaceName
4345+ , nodeNetIfaceAddress :: Server
4346+ } deriving (Eq, Show, Generic, Typeable)
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)
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)
4376+data ThreadPoolSize = ThreadPoolBounded Int
4377+ | ThreadPoolUnbounded
4378+ deriving (Eq, Show, Generic, Typeable)
4380+data ThreadPoolType = ThreadPoolScaling
4383+ deriving (Eq, Show, Generic, Typeable)
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)
4398+-- | Handles quirks in the way JVM versions are rendered (1.7.0_101 -> 1.7.0.101)
4399+newtype JVMVersion = JVMVersion { unJVMVersion :: VersionNumber }
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)
4409+newtype JVMMemoryPool = JVMMemoryPool {
4410+ jvmMemoryPool :: Text
4411+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
4413+newtype JVMGCCollector = JVMGCCollector {
4414+ jvmGCCollector :: Text
4415+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
4419+ } deriving (Eq, Show, Generic, Typeable, FromJSON)
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)
4429+data CPUInfo = CPUInfo {
4430+ cpuCacheSize :: Bytes
4431+ , cpuCoresPerSocket :: Int
4432+ , cpuTotalSockets :: Int
4433+ , cpuTotalCores :: Int
4436+ , cpuVendor :: Text
4437+ } deriving (Eq, Show, Generic, Typeable)
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)
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)
4456+-- | Reasonable defaults for repo creation/update
4458+-- * repoUpdateVerify True
4459+defaultSnapshotRepoUpdateSettings :: SnapshotRepoUpdateSettings
4460+defaultSnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings True
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)
4479+instance SnapshotRepo FsSnapshotRepo where
4480+ toGSnapshotRepo FsSnapshotRepo {..} =
4481+ GenericSnapshotRepo fsrName fsRepoType (GenericSnapshotRepoSettings settings)
4483+ Object settings = object $ [ "location" .= fsrLocation
4484+ , "compress" .= fsrCompressMetadata
4486+ optionalPairs = catMaybes [ ("chunk_size" .=) <$> fsrChunkSize
4487+ , ("max_restore_bytes_per_sec" .=) <$> fsrMaxRestoreBytesPerSec
4488+ , ("max_snapshot_bytes_per_sec" .=) <$> fsrMaxSnapshotBytesPerSec
4490+ fromGSnapshotRepo GenericSnapshotRepo {..}
4491+ | gSnapshotRepoType == fsRepoType = do
4492+ let o = gSnapshotRepoSettingsObject gSnapshotRepoSettings
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)
4502+parseRepo :: Parser a -> Either SnapshotRepoConversionError a
4503+parseRepo parser = case parseEither (const parser) () of
4504+ Left e -> Left (OtherRepoConversionError (T.pack e))
4508+fsRepoType :: SnapshotRepoType
4509+fsRepoType = SnapshotRepoType "fs"
4511+-- | Law: fromGSnapshotRepo (toGSnapshotRepo r) == Right r
4512+class SnapshotRepo r where
4513+ toGSnapshotRepo :: r -> GenericSnapshotRepo
4514+ fromGSnapshotRepo :: GenericSnapshotRepo -> Either SnapshotRepoConversionError r
4517+data SnapshotRepoConversionError = RepoTypeMismatch SnapshotRepoType SnapshotRepoType
4518+ -- ^ Expected type and actual type
4519+ | OtherRepoConversionError Text
4520+ deriving (Show, Eq, Generic, Typeable)
4523+instance Exception SnapshotRepoConversionError
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)
4546+-- | Reasonable defaults for snapshot creation
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
4563+data SnapshotSelection = SnapshotList (NonEmpty SnapshotPattern)
4564+ | AllSnapshots deriving (Eq, Generic, Show, Typeable)
4567+-- | Either specifies an exact snapshot name or one with globs in it,
4568+-- e.g. @SnapPattern "foo*"@ __NOTE__: Patterns are not supported on
4570+data SnapshotPattern = ExactSnap SnapshotName
4572+ deriving (Eq, Generic, Show, Typeable)
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)
4589+instance FromJSON SnapshotInfo where
4590+ parseJSON = withObject "SnapshotInfo" parse
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")
4599+ <*> o .: "snapshot"
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)
4609+instance FromJSON SnapshotShardFailure where
4610+ parseJSON = withObject "SnapshotShardFailure" parse
4612+ parse o = SnapshotShardFailure <$> o .: "index"
4613+ <*> o .:? "node_id"
4615+ <*> o .: "shard_id"
4618+newtype ShardId = ShardId { shardId :: Int }
4619+ deriving (Eq, Show, Generic, Typeable, FromJSON)
4622+newtype MS = MS NominalDiffTime
4625+-- keeps the unexported constructor warnings at bay
4626+unMS :: MS -> NominalDiffTime
4630+instance FromJSON MS where
4631+ parseJSON = withScientific "MS" (return . MS . parse)
4633+ parse n = fromInteger ((truncate n) * 1000)
4636+data SnapshotState = SnapshotInit
4643+ deriving (Show, Eq, Generic, Typeable)
4645+instance FromJSON SnapshotState where
4646+ parseJSON = withText "SnapshotState" parse
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)
4658+newtype SnapshotName = SnapshotName { snapshotName :: Text }
4659+ deriving (Show, Eq, Ord, Generic, Typeable, ToJSON, FromJSON)
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
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)
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)
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
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)
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)
4725+instance Bounded RRGroupRefNum where
4726+ minBound = RRGroupRefNum 1
4727+ maxBound = RRGroupRefNum 9
4730+-- | Only allows valid group number references (1-9).
4731+mkRRGroupRefNum :: Int -> Maybe RRGroupRefNum
4733+ | i >= (rrGroupRefNum minBound) && i <= (rrGroupRefNum maxBound) =
4734+ Just $ RRGroupRefNum i
4735+ | otherwise = Nothing
4738+-- | Reasonable defaults for snapshot restores
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
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)
4773+instance ToJSON RestoreIndexSettings where
4774+ toJSON RestoreIndexSettings {..} = object prs
4776+ prs = catMaybes [("index.number_of_replicas" .=) <$> restoreOverrideReplicas]
4779+instance FromJSON NodesInfo where
4780+ parseJSON = withObject "NodesInfo" parse
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)
4790+instance FromJSON NodesStats where
4791+ parseJSON = withObject "NodesStats" parse
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)
4801+instance FromJSON NodeBreakerStats where
4802+ parseJSON = withObject "NodeBreakerStats" parse
4804+ parse o = NodeBreakerStats <$> o .: "tripped"
4805+ <*> o .: "overhead"
4806+ <*> o .: "estimated_size_in_bytes"
4807+ <*> o .: "limit_size_in_bytes"
4809+instance FromJSON NodeHTTPStats where
4810+ parseJSON = withObject "NodeHTTPStats" parse
4812+ parse o = NodeHTTPStats <$> o .: "total_opened"
4813+ <*> o .: "current_open"
4815+instance FromJSON NodeTransportStats where
4816+ parseJSON = withObject "NodeTransportStats" parse
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"
4824+instance FromJSON NodeFSStats where
4825+ parseJSON = withObject "NodeFSStats" parse
4827+ parse o = NodeFSStats <$> o .: "data"
4829+ <*> (posixMS <$> o .: "timestamp")
4831+instance FromJSON NodeDataPathStats where
4832+ parseJSON = withObject "NodeDataPathStats" parse
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"
4851+newtype StringlyTypedDouble = StringlyTypedDouble { unStringlyTypedDouble :: Double }
4854+instance FromJSON StringlyTypedDouble where
4855+ parseJSON = fmap StringlyTypedDouble . parseJSON . unStringlyTypeJSON
4858+instance FromJSON NodeFSTotalStats where
4859+ parseJSON = withObject "NodeFSTotalStats" parse
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"
4873+instance FromJSON NodeNetworkStats where
4874+ parseJSON = withObject "NodeNetworkStats" parse
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"
4889+instance FromJSON NodeThreadPoolsStats where
4890+ parseJSON = withObject "NodeThreadPoolsStats" parse
4892+ parse o = NodeThreadPoolsStats <$> o .: "snapshot"
4896+ <*> o .: "management"
4897+ <*> o .:? "fetch_shard_store"
4898+ <*> o .: "optimize"
4906+ <*> o .:? "listener"
4907+ <*> o .:? "fetch_shard_started"
4908+ <*> o .: "percolate"
4909+instance FromJSON NodeThreadPoolStats where
4910+ parseJSON = withObject "NodeThreadPoolStats" parse
4912+ parse o = NodeThreadPoolStats <$> o .: "completed"
4914+ <*> o .: "rejected"
4919+instance FromJSON NodeJVMStats where
4920+ parseJSON = withObject "NodeJVMStats" parse
4923+ bufferPools <- o .: "buffer_pools"
4924+ mapped <- bufferPools .: "mapped"
4925+ direct <- bufferPools .: "direct"
4927+ collectors <- gc .: "collectors"
4928+ oldC <- collectors .: "old"
4929+ youngC <- collectors .: "young"
4930+ threads <- o .: "threads"
4932+ pools <- mem .: "pools"
4933+ oldM <- pools .: "old"
4934+ survivorM <- pools .: "survivor"
4935+ youngM <- pools .: "young"
4936+ NodeJVMStats <$> pure mapped
4940+ <*> threads .: "peak_count"
4941+ <*> threads .: "count"
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")
4954+instance FromJSON JVMBufferPoolStats where
4955+ parseJSON = withObject "JVMBufferPoolStats" parse
4957+ parse o = JVMBufferPoolStats <$> o .: "total_capacity_in_bytes"
4958+ <*> o .: "used_in_bytes"
4961+instance FromJSON JVMGCStats where
4962+ parseJSON = withObject "JVMGCStats" parse
4964+ parse o = JVMGCStats <$> (unMS <$> o .: "collection_time_in_millis")
4965+ <*> o .: "collection_count"
4967+instance FromJSON JVMPoolStats where
4968+ parseJSON = withObject "JVMPoolStats" parse
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"
4975+instance FromJSON NodeProcessStats where
4976+ parseJSON = withObject "NodeProcessStats" parse
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")
4991+instance FromJSON NodeOSStats where
4992+ parseJSON = withObject "NodeOSStats" parse
4995+ swap <- o .: "swap"
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"
5013+ <*> (unMS <$> o .: "uptime_in_millis")
5014+ <*> (posixMS <$> o .: "timestamp")
5016+instance FromJSON LoadAvgs where
5017+ parseJSON = withArray "LoadAvgs" parse
5019+ parse v = case V.toList v of
5020+ [one, five, fifteen] -> LoadAvgs <$> parseJSON one
5022+ <*> parseJSON fifteen
5023+ _ -> fail "Expecting a triple of Doubles"
5025+instance FromJSON NodeIndicesStats where
5026+ parseJSON = withObject "NodeIndicesStats" parse
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"
5122+instance FromJSON NodeBreakersStats where
5123+ parseJSON = withObject "NodeBreakersStats" parse
5125+ parse o = NodeBreakersStats <$> o .: "parent"
5127+ <*> o .: "fielddata"
5129+parseNodeStats :: FullNodeId -> Object -> Parser NodeStats
5130+parseNodeStats fnid o = do
5131+ NodeStats <$> o .: "name"
5133+ <*> o .:? "breakers"
5135+ <*> o .: "transport"
5138+ <*> o .: "thread_pool"
5144+parseNodeInfo :: FullNodeId -> Object -> Parser NodeInfo
5145+parseNodeInfo nid o =
5146+ NodeInfo <$> o .: "http_address"
5151+ <*> o .: "transport_address"
5156+ <*> o .: "transport"
5158+ <*> o .: "thread_pool"
5162+ <*> o .: "settings"
5164+instance FromJSON NodePluginInfo where
5165+ parseJSON = withObject "NodePluginInfo" parse
5167+ parse o = NodePluginInfo <$> o .: "site"
5169+ <*> o .: "description"
5173+instance FromJSON NodeHTTPInfo where
5174+ parseJSON = withObject "NodeHTTPInfo" parse
5176+ parse o = NodeHTTPInfo <$> o .: "max_content_length_in_bytes"
5177+ <*> parseJSON (Object o)
5179+instance FromJSON BoundTransportAddress where
5180+ parseJSON = withObject "BoundTransportAddress" parse
5182+ parse o = BoundTransportAddress <$> o .: "publish_address"
5183+ <*> o .: "bound_address"
5185+instance FromJSON NodeOSInfo where
5186+ parseJSON = withObject "NodeOSInfo" parse
5189+ swap <- o .: "swap"
5191+ NodeOSInfo <$> swap .: "total_in_bytes"
5192+ <*> mem .: "total_in_bytes"
5194+ <*> o .: "available_processors"
5195+ <*> (unMS <$> o .: "refresh_interval_in_millis")
5198+instance FromJSON CPUInfo where
5199+ parseJSON = withObject "CPUInfo" parse
5201+ parse o = CPUInfo <$> o .: "cache_size_in_bytes"
5202+ <*> o .: "cores_per_socket"
5203+ <*> o .: "total_sockets"
5204+ <*> o .: "total_cores"
5209+instance FromJSON NodeProcessInfo where
5210+ parseJSON = withObject "NodeProcessInfo" parse
5212+ parse o = NodeProcessInfo <$> o .: "mlockall"
5213+ <*> o .: "max_file_descriptors"
5215+ <*> (unMS <$> o .: "refresh_interval_in_millis")
5217+instance FromJSON NodeJVMInfo where
5218+ parseJSON = withObject "NodeJVMInfo" parse
5220+ parse o = NodeJVMInfo <$> o .: "memory_pools"
5221+ <*> o .: "gc_collectors"
5223+ <*> (posixMS <$> o .: "start_time_in_millis")
5224+ <*> o .: "vm_vendor"
5225+ <*> o .: "vm_version"
5227+ <*> (unJVMVersion <$> o .: "version")
5230+instance FromJSON JVMVersion where
5231+ parseJSON (String t) =
5232+ JVMVersion <$> parseJSON (String (T.replace "_" "." t))
5233+ parseJSON v = JVMVersion <$> parseJSON v
5235+instance FromJSON JVMMemoryInfo where
5236+ parseJSON = withObject "JVMMemoryInfo" parse
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"
5244+instance FromJSON NodeThreadPoolsInfo where
5245+ parseJSON = withObject "NodeThreadPoolsInfo" parse
5247+ parse o = NodeThreadPoolsInfo <$> o .: "refresh"
5248+ <*> o .: "management"
5249+ <*> o .: "percolate"
5250+ <*> o .:? "listener"
5251+ <*> o .:? "fetch_shard_started"
5255+ <*> o .: "optimize"
5259+ <*> o .: "snapshot"
5261+ <*> o .:? "fetch_shard_store"
5265+instance FromJSON NodeThreadPoolInfo where
5266+ parseJSON = withObject "NodeThreadPoolInfo" parse
5269+ ka <- maybe (return Nothing) (fmap Just . parseStringInterval) =<< o .:? "keep_alive"
5270+ NodeThreadPoolInfo <$> (parseJSON . unStringlyTypeJSON =<< o .: "queue_size")
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"
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
5290+instance FromJSON ThreadPoolSize where
5291+ parseJSON v = parseAsNumber v <|> parseAsString v
5293+ parseAsNumber = parseAsInt <=< parseJSON
5294+ parseAsInt (-1) = return ThreadPoolUnbounded
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)
5304+instance FromJSON ThreadPoolType where
5305+ parseJSON = withText "ThreadPoolType" parse
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)
5312+instance FromJSON NodeTransportInfo where
5313+ parseJSON = withObject "NodeTransportInfo" parse
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"
5322+instance FromJSON NodeNetworkInfo where
5323+ parseJSON = withObject "NodeNetworkInfo" parse
5325+ parse o = NodeNetworkInfo <$> o .: "primary_interface"
5326+ <*> (unMS <$> o .: "refresh_interval_in_millis")
5329+instance FromJSON NodeNetworkInterface where
5330+ parseJSON = withObject "NodeNetworkInterface" parse
5332+ parse o = NodeNetworkInterface <$> o .: "mac_address"
5336+newtype MaybeNA a = MaybeNA { unMaybeNA :: Maybe a }
5337+ deriving (Show, Eq)
5339+instance FromJSON a => FromJSON (MaybeNA a) where
5340+ parseJSON (String "NA") = pure $ MaybeNA Nothing
5341+ parseJSON o = MaybeNA . Just <$> parseJSON o
5344+data Suggest = Suggest { suggestText :: Text
5345+ , suggestName :: Text
5346+ , suggestType :: SuggestType
5348+ deriving (Show, Generic, Eq, Read, Typeable)
5350+instance ToJSON Suggest where
5351+ toJSON Suggest{..} = object [ "text" .= suggestText
5352+ , suggestName .= suggestType
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
5366+data SuggestType = SuggestTypePhraseSuggester PhraseSuggester
5367+ deriving (Show, Generic, Eq, Read, Typeable)
5369+instance ToJSON SuggestType where
5370+ toJSON (SuggestTypePhraseSuggester x) = object ["phrase" .= x]
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
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]
5392+ deriving (Show, Generic, Eq, Read, Typeable)
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
5409+instance FromJSON PhraseSuggester where
5410+ parseJSON = withObject "PhraseSuggester" parse
5411+ where parse o = PhraseSuggester
5413+ <*> o .:? "gram_size"
5414+ <*> o .:? "real_word_error_likelihood"
5415+ <*> o .:? "confidence"
5416+ <*> o .:? "max_errors"
5417+ <*> o .:? "separator"
5419+ <*> o .:? "analyzer"
5420+ <*> o .:? "shard_size"
5421+ <*> o .:? "highlight"
5422+ <*> o .:? "collate"
5423+ <*> o .:? "direct_generator" .!= []
5425+mkPhraseSuggester :: FieldName -> PhraseSuggester
5426+mkPhraseSuggester fName =
5427+ PhraseSuggester fName Nothing Nothing Nothing Nothing Nothing Nothing
5428+ Nothing Nothing Nothing Nothing []
5430+data PhraseSuggesterHighlighter =
5431+ PhraseSuggesterHighlighter { phraseSuggesterHighlighterPreTag :: Text
5432+ , phraseSuggesterHighlighterPostTag :: Text
5434+ deriving (Show, Generic, Eq, Read, Typeable)
5436+instance ToJSON PhraseSuggesterHighlighter where
5437+ toJSON PhraseSuggesterHighlighter{..} =
5438+ object [ "pre_tag" .= phraseSuggesterHighlighterPreTag
5439+ , "post_tag" .= phraseSuggesterHighlighterPostTag
5442+instance FromJSON PhraseSuggesterHighlighter where
5443+ parseJSON = withObject "PhraseSuggesterHighlighter" parse
5444+ where parse o = PhraseSuggesterHighlighter
5446+ <*> o .: "post_tag"
5448+data PhraseSuggesterCollate =
5449+ PhraseSuggesterCollate { phraseSuggesterCollateTemplateQuery :: TemplateQueryInline
5450+ , phraseSuggesterCollatePrune :: Bool
5452+ deriving (Show, Generic, Eq, Read, Typeable)
5454+instance ToJSON PhraseSuggesterCollate where
5455+ toJSON PhraseSuggesterCollate{..} = object [ "query" .= object
5456+ [ "inline" .= (inline phraseSuggesterCollateTemplateQuery)
5458+ , "params" .= (params phraseSuggesterCollateTemplateQuery)
5459+ , "prune" .= phraseSuggesterCollatePrune
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
5471+data SuggestOptions =
5472+ SuggestOptions { suggestOptionsText :: Text
5473+ , suggestOptionsScore :: Double
5474+ , suggestOptionsFreq :: Maybe Int
5475+ , suggestOptionsHighlighted :: Maybe Text
5477+ deriving (Eq, Read, Show)
5479+instance FromJSON SuggestOptions where
5480+ parseJSON = withObject "SuggestOptions" parse
5481+ where parse o = SuggestOptions
5485+ <*> o .:? "highlighted"
5487+data SuggestResponse =
5488+ SuggestResponse { suggestResponseText :: Text
5489+ , suggestResponseOffset :: Int
5490+ , suggestResponseLength :: Int
5491+ , suggestResponseOptions :: [SuggestOptions]
5493+ deriving (Eq, Read, Show)
5495+instance FromJSON SuggestResponse where
5496+ parseJSON = withObject "SuggestResponse" parse
5497+ where parse o = SuggestResponse
5503+data NamedSuggestionResponse =
5504+ NamedSuggestionResponse { nsrName :: Text
5505+ , nsrResponses :: [SuggestResponse]
5507+ deriving (Eq, Read, Show)
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'
5517+ parseJSON x = typeMismatch "NamedSuggestionResponse" x
5519+data DirectGeneratorSuggestModeTypes = DirectGeneratorSuggestModeMissing
5520+ | DirectGeneratorSuggestModePopular
5521+ | DirectGeneratorSuggestModeAlways
5522+ deriving (Show, Eq, Read, Generic, Typeable)
5524+instance ToJSON DirectGeneratorSuggestModeTypes where
5525+ toJSON DirectGeneratorSuggestModeMissing = "missing"
5526+ toJSON DirectGeneratorSuggestModePopular = "popular"
5527+ toJSON DirectGeneratorSuggestModeAlways = "always"
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)
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
5549+ deriving (Show, Eq, Read, Generic, Typeable)
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
5566+instance FromJSON DirectGenerators where
5567+ parseJSON = withObject "DirectGenerators" parse
5568+ where parse o = DirectGenerators
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"
5581+mkDirectGenerators :: FieldName -> DirectGenerators
5582+mkDirectGenerators fn = DirectGenerators fn Nothing DirectGeneratorSuggestModeMissing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing