@@ -1,7 +1,10 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE DeriveGeneric #-}
1{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7+-- {-# LANGUAGE NoMonomorphismRestriction #-}
5{-# LANGUAGE NamedFieldPuns #-}
8{-# LANGUAGE NamedFieldPuns #-}
6{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE RecordWildCards #-}
@@ -10,11 +13,11 @@
10-------------------------------------------------------------------------------
13-------------------------------------------------------------------------------
12-- Module : Database.Bloodhound.Types
15-- Module : Database.Bloodhound.Types
13−-- Copyright : (C) 2014, 2018 Chris Allen
16+-- Copyright : (C) 2014, 2015, 2016 Chris Allen
14-- License : BSD-style (see the file LICENSE)
17-- License : BSD-style (see the file LICENSE)
15-- Maintainer : Chris Allen <cma@bitemyapp.com
18-- Maintainer : Chris Allen <cma@bitemyapp.com
16-- Stability : provisional
19-- Stability : provisional
17−-- Portability : RecordWildCards
20+-- Portability : DeriveGeneric, RecordWildCards
19-- Data types for describing actions and data structures performed to interact
22-- Data types for describing actions and data structures performed to interact
20-- with Elasticsearch. The two main buckets your queries against Elasticsearch
23-- with Elasticsearch. The two main buckets your queries against Elasticsearch
@@ -42,15 +45,11 @@ module Database.Bloodhound.Types
42 , mkTermsAggregation
45 , mkTermsAggregation
43 , mkTermsScriptAggregation
46 , mkTermsScriptAggregation
44 , mkDateHistogram
47 , mkDateHistogram
45− , mkCardinalityAggregation
46 , mkDocVersion
48 , mkDocVersion
48− , mkExtendedStatsAggregation
49 , docVersionNumber
49 , docVersionNumber
50 , toMissing
50 , toMissing
52 , toDateHistogram
52 , toDateHistogram
54 , omitNulls
53 , omitNulls
@@ -61,9 +60,6 @@ module Database.Bloodhound.Types
62 , MonadBH(..)
61 , MonadBH(..)
63 , Version(..)
62 , Version(..)
67 , Status(..)
63 , Status(..)
68 , Existence(..)
64 , Existence(..)
69 , NullValue(..)
65 , NullValue(..)
@@ -71,7 +67,6 @@ module Database.Bloodhound.Types
71 , UpdatableIndexSetting(..)
67 , UpdatableIndexSetting(..)
72 , IndexSettingsSummary(..)
68 , IndexSettingsSummary(..)
73 , AllocationPolicy(..)
69 , AllocationPolicy(..)
75 , ReplicaBounds(..)
70 , ReplicaBounds(..)
76 , Bytes(..)
71 , Bytes(..)
77 , gigabytes
72 , gigabytes
@@ -120,8 +115,8 @@ module Database.Bloodhound.Types
120 , Pattern(..)
115 , Pattern(..)
121 , ShardResult(..)
116 , ShardResult(..)
122 , Hit(..)
117 , Hit(..)
124 , Filter(..)
118 , Filter(..)
125 , BoolMatch(..)
120 , BoolMatch(..)
126 , Term(..)
121 , Term(..)
127 , GeoPoint(..)
122 , GeoPoint(..)
@@ -148,22 +143,11 @@ module Database.Bloodhound.Types
148 , RegexpFlags(..)
143 , RegexpFlags(..)
149 , RegexpFlag(..)
144 , RegexpFlag(..)
150 , FieldName(..)
145 , FieldName(..)
154 , Script(..)
146 , Script(..)
155− , ScriptLanguage(..)
161 , IndexName(..)
147 , IndexName(..)
162 , IndexSelection(..)
148 , IndexSelection(..)
163− , NodeSelection(..)
149+ , IndexOptimizationSettings(..)
164− , NodeSelector(..)
150+ , defaultIndexOptimizationSettings
165− , ForceMergeIndexSettings(..)
166− , defaultForceMergeIndexSettings
167 , TemplateName(..)
151 , TemplateName(..)
168 , TemplatePattern(..)
152 , TemplatePattern(..)
169 , MappingName(..)
153 , MappingName(..)
@@ -187,19 +171,8 @@ module Database.Bloodhound.Types
187 , BoolQuery(..)
171 , BoolQuery(..)
188 , BoostingQuery(..)
172 , BoostingQuery(..)
189 , CommonTermsQuery(..)
173 , CommonTermsQuery(..)
190− , FunctionScoreQuery(..)
193− , FunctionScoreFunctions(..)
194− , ComponentFunctionScoreFunction(..)
195− , FunctionScoreFunction(..)
198− , FieldValueFactor(..)
200− , FactorModifier(..)
201− , FactorMissingFieldValue(..)
202 , DisMaxQuery(..)
174 , DisMaxQuery(..)
203 , FuzzyLikeThisQuery(..)
176 , FuzzyLikeThisQuery(..)
204 , FuzzyLikeFieldQuery(..)
177 , FuzzyLikeFieldQuery(..)
205 , FuzzyQuery(..)
178 , FuzzyQuery(..)
@@ -215,16 +188,10 @@ module Database.Bloodhound.Types
215 , RangeQuery(..)
188 , RangeQuery(..)
216 , RegexpQuery(..)
189 , RegexpQuery(..)
217 , QueryString(..)
190 , QueryString(..)
218− , TemplateQueryInline(..)
219− , TemplateQueryKeyValuePairs(..)
221 , BooleanOperator(..)
191 , BooleanOperator(..)
222 , ZeroTermsQuery(..)
192 , ZeroTermsQuery(..)
223 , CutoffFrequency(..)
193 , CutoffFrequency(..)
224 , Analyzer(..)
194 , Analyzer(..)
228 , MaxExpansions(..)
195 , MaxExpansions(..)
229 , Lenient(..)
196 , Lenient(..)
230 , MatchQueryType(..)
197 , MatchQueryType(..)
@@ -285,81 +252,7 @@ module Database.Bloodhound.Types
285 , SnapshotNodeVerification(..)
252 , SnapshotNodeVerification(..)
286 , FullNodeId(..)
253 , FullNodeId(..)
287 , NodeName(..)
254 , NodeName(..)
292− , NodeBreakersStats(..)
293− , NodeBreakerStats(..)
295− , NodeTransportStats(..)
297− , NodeDataPathStats(..)
298− , NodeFSTotalStats(..)
299− , NodeNetworkStats(..)
300− , NodeThreadPoolsStats(..)
301− , NodeThreadPoolStats(..)
303− , JVMBufferPoolStats(..)
306− , NodeProcessStats(..)
309− , NodeIndicesStats(..)
313− , NodePluginInfo(..)
315− , NodeTransportInfo(..)
316− , BoundTransportAddress(..)
317− , NodeNetworkInfo(..)
319− , NetworkInterfaceName(..)
320− , NodeNetworkInterface(..)
321− , NodeThreadPoolsInfo(..)
322− , NodeThreadPoolInfo(..)
323− , ThreadPoolSize(..)
324− , ThreadPoolType(..)
327− , JVMGCCollector(..)
332− , NodeProcessInfo(..)
333 , FsSnapshotRepo(..)
255 , FsSnapshotRepo(..)
334− , SnapshotCreateSettings(..)
335− , defaultSnapshotCreateSettings
336− , SnapshotSelection(..)
337− , SnapshotPattern(..)
339− , SnapshotShardFailure(..)
343− , SnapshotRestoreSettings(..)
344− , defaultSnapshotRestoreSettings
345− , RestoreRenamePattern(..)
346− , RestoreRenameToken(..)
350− , RestoreIndexSettings(..)
353− , PhraseSuggester(..)
354− , PhraseSuggesterHighlighter(..)
355− , PhraseSuggesterCollate(..)
357− , SuggestOptions(..)
358− , SuggestResponse(..)
359− , NamedSuggestionResponse(..)
360− , DirectGenerators(..)
361− , mkDirectGenerators
362− , DirectGeneratorSuggestModeTypes (..)
364 , Aggregation(..)
257 , Aggregation(..)
365 , Aggregations
258 , Aggregations
@@ -371,8 +264,6 @@ module Database.Bloodhound.Types
371 , MissingAggregation(..)
264 , MissingAggregation(..)
372 , ValueCountAggregation(..)
265 , ValueCountAggregation(..)
373 , FilterAggregation(..)
266 , FilterAggregation(..)
374− , CardinalityAggregation(..)
375− , MaxAggregation(..)
376 , DateHistogramAggregation(..)
267 , DateHistogramAggregation(..)
377 , DateRangeAggregation(..)
268 , DateRangeAggregation(..)
378 , DateRangeAggRange(..)
269 , DateRangeAggRange(..)
@@ -380,9 +271,6 @@ module Database.Bloodhound.Types
380 , DateMathAnchor(..)
271 , DateMathAnchor(..)
381 , DateMathModifier(..)
272 , DateMathModifier(..)
382 , DateMathUnit(..)
273 , DateMathUnit(..)
383− , TopHitsAggregation(..)
384− , StatisticsAggregation(..)
387 , Highlights(..)
275 , Highlights(..)
388 , FieldHighlight(..)
276 , FieldHighlight(..)
@@ -400,32 +288,697 @@ module Database.Bloodhound.Types
400 , TermsResult(..)
288 , TermsResult(..)
401 , DateHistogramResult(..)
289 , DateHistogramResult(..)
402 , DateRangeResult(..)
290 , DateRangeResult(..)
405 , EsUsername(..)
292 , EsUsername(..)
406 , EsPassword(..)
293 , EsPassword(..)
408− , Analysis(..)
296+import Control.Applicative as A
409− , AnalyzerDefinition(..)
297+import Control.Monad.Catch
410− , TokenizerDefinition(..)
298+import Control.Monad.Except
411− , TokenFilterDefinition(..)
299+import Control.Monad.Reader
412− , CharFilterDefinition(..)
300+import Control.Monad.State
413− , Ngram(..)
301+import Control.Monad.Writer
414− , TokenChar(..)
302+import Data.Aeson
415− , Shingle(..)
303+import Data.Aeson.Types (Pair, Parser, emptyObject,
416− , Language(..)
304+ parseEither, parseMaybe)
417− ) where
305+import qualified Data.ByteString.Lazy.Char8 as L
419−import Bloodhound.Import
307+import Data.Hashable (Hashable)
420−
308+import qualified Data.HashMap.Strict as HM
421−import Database.Bloodhound.Internal.Aggregation
309+import Data.List (foldl', nub)
422−import Database.Bloodhound.Internal.Analysis
310+import Data.List.NonEmpty (NonEmpty (..), toList)
423−import Database.Bloodhound.Internal.Client
311+import qualified Data.Map.Strict as M
424−import Database.Bloodhound.Internal.Highlight
312+import Data.Maybe
425−import Database.Bloodhound.Internal.Newtypes
313+import Data.Scientific (Scientific)
426−import Database.Bloodhound.Internal.Query
314+import Data.Text (Text)
427−import Database.Bloodhound.Internal.Sort
315+import qualified Data.Text as T
428−import Database.Bloodhound.Internal.Suggest
316+import Data.Time.Calendar
317+import Data.Time.Clock (NominalDiffTime, UTCTime)
318+import Data.Time.Clock.POSIX
319+import qualified Data.Traversable as DT
320+import Data.Typeable (Typeable)
321+import qualified Data.Vector as V
323+import GHC.Generics (Generic)
324+import Network.HTTP.Client
325+import qualified Network.HTTP.Types.Method as NHTM
326+import qualified Text.Read as TR
328+import Database.Bloodhound.Types.Class
329+import Database.Bloodhound.Types.Internal
332+-- >>> :set -XOverloadedStrings
333+-- >>> import Data.Aeson
334+-- >>> import Database.Bloodhound
335+-- >>> let testServer = (Server "http://localhost:9200")
336+-- >>> let testIndex = IndexName "twitter"
337+-- >>> let testMapping = MappingName "tweet"
338+-- >>> let defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
340+-- defaultIndexSettings is exported by Database.Bloodhound as well
341+-- no trailing slashes in servers, library handles building the path.
343+-- | Create a 'BHEnv' with all optional fields defaulted. HTTP hook
344+-- will be a noop. You can use the exported fields to customize it further, e.g.:
346+-- >> (mkBHEnv myServer myManager) { bhRequestHook = customHook }
347+mkBHEnv :: Server -> Manager -> BHEnv
348+mkBHEnv s m = BHEnv s m return
350+newtype BH m a = BH {
351+ unBH :: ReaderT BHEnv m a
352+ } deriving ( Functor
366+instance MonadTrans BH where
369+instance (MonadReader r m) => MonadReader r (BH m) where
371+ local f (BH (ReaderT m)) = BH $ ReaderT $ \r ->
374+instance (Functor m, Applicative m, MonadIO m) => MonadBH (BH m) where
375+ getBHEnv = BH getBHEnv
377+runBH :: BHEnv -> BH m a -> m a
378+runBH e f = runReaderT (unBH f) e
380+{-| 'Version' is embedded in 'Status' -}
381+data Version = Version { number :: Text
382+ , build_hash :: Text
383+ , build_timestamp :: UTCTime
384+ , build_snapshot :: Bool
385+ , lucene_version :: Text } deriving (Eq, Read, Show, Generic, Typeable)
387+{-| 'Status' is a data type for describing the JSON body returned by
388+ Elasticsearch when you query its status. This was deprecated in 1.2.0.
390+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-status.html#indices-status>
393+data Status = Status { ok :: Maybe Bool
396+ , version :: Version
397+ , tagline :: Text } deriving (Eq, Read, Show, Generic)
399+{-| 'IndexSettings' is used to configure the shards and replicas when you create
400+ an Elasticsearch Index.
402+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html>
406+ IndexSettings { indexShards :: ShardCount
407+ , indexReplicas :: ReplicaCount } deriving (Eq, Read, Show, Generic, Typeable)
409+{-| 'defaultIndexSettings' is an 'IndexSettings' with 3 shards and 2 replicas. -}
410+defaultIndexSettings :: IndexSettings
411+defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
414+{-| 'IndexOptimizationSettings' is used to configure index optimization. See
415+ <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-optimize.html>
418+data IndexOptimizationSettings =
419+ IndexOptimizationSettings { maxNumSegments :: Maybe Int
420+ -- ^ 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.
421+ , onlyExpungeDeletes :: Bool
422+ -- ^ 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.
423+ , flushAfterOptimize :: Bool
424+ -- ^ Should a flush be performed after the optimize.
425+ } deriving (Eq, Show, Generic, Typeable)
428+{-| 'defaultIndexOptimizationSettings' implements the default settings that
429+ ElasticSearch uses for index optimization. 'maxNumSegments' is Nothing,
430+ 'onlyExpungeDeletes' is False, and flushAfterOptimize is True.
432+defaultIndexOptimizationSettings :: IndexOptimizationSettings
433+defaultIndexOptimizationSettings = IndexOptimizationSettings Nothing False True
435+{-| 'UpdatableIndexSetting' are settings which may be updated after an index is created.
437+ <https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html>
439+data UpdatableIndexSetting = NumberOfReplicas ReplicaCount
440+ -- ^ The number of replicas each shard has.
441+ | AutoExpandReplicas ReplicaBounds
442+ | BlocksReadOnly Bool
443+ -- ^ Set to True to have the index read only. False to allow writes and metadata changes.
445+ -- ^ Set to True to disable read operations against the index.
447+ -- ^ Set to True to disable write operations against the index.
448+ | BlocksMetaData Bool
449+ -- ^ Set to True to disable metadata operations against the index.
450+ | RefreshInterval NominalDiffTime
451+ -- ^ The async refresh interval of a shard
452+ | IndexConcurrency Int
453+ | FailOnMergeFailure Bool
454+ | TranslogFlushThresholdOps Int
455+ -- ^ When to flush on operations.
456+ | TranslogFlushThresholdSize Bytes
457+ -- ^ When to flush based on translog (bytes) size.
458+ | TranslogFlushThresholdPeriod NominalDiffTime
459+ -- ^ When to flush based on a period of not flushing.
460+ | TranslogDisableFlush Bool
461+ -- ^ Disables flushing. Note, should be set for a short interval and then enabled.
462+ | CacheFilterMaxSize (Maybe Bytes)
463+ -- ^ The maximum size of filter cache (per segment in shard).
464+ | CacheFilterExpire (Maybe NominalDiffTime)
465+ -- ^ The expire after access time for filter cache.
466+ | GatewaySnapshotInterval NominalDiffTime
467+ -- ^ The gateway snapshot interval (only applies to shared gateways).
468+ | RoutingAllocationInclude (NonEmpty NodeAttrFilter)
469+ -- ^ A node matching any rule will be allowed to host shards from the index.
470+ | RoutingAllocationExclude (NonEmpty NodeAttrFilter)
471+ -- ^ A node matching any rule will NOT be allowed to host shards from the index.
472+ | RoutingAllocationRequire (NonEmpty NodeAttrFilter)
473+ -- ^ Only nodes matching all rules will be allowed to host shards from the index.
474+ | RoutingAllocationEnable AllocationPolicy
475+ -- ^ Enables shard allocation for a specific index.
476+ | RoutingAllocationShardsPerNode ShardCount
477+ -- ^ Controls the total number of shards (replicas and primaries) allowed to be allocated on a single node.
478+ | RecoveryInitialShards InitialShardCount
479+ -- ^ When using local gateway a particular shard is recovered only if there can be allocated quorum shards in the cluster.
480+ | GCDeletes NominalDiffTime
481+ | TTLDisablePurge Bool
482+ -- ^ Disables temporarily the purge of expired docs.
483+ | TranslogFSType FSType
484+ | IndexCompoundFormat CompoundFormat
485+ | IndexCompoundOnFlush Bool
486+ | WarmerEnabled Bool
487+ deriving (Eq, Show, Generic, Typeable)
489+data AllocationPolicy = AllocAll
490+ -- ^ Allows shard allocation for all shards.
492+ -- ^ Allows shard allocation only for primary shards.
494+ -- ^ Allows shard allocation only for primary shards for new indices.
496+ -- ^ No shard allocation is allowed
497+ deriving (Eq, Read, Show, Generic, Typeable)
499+data ReplicaBounds = ReplicasBounded Int Int
500+ | ReplicasLowerBounded Int
502+ deriving (Eq, Read, Show, Generic, Typeable)
504+-- | A measure of bytes used for various configurations. You may want
505+-- to use smart constructors like 'gigabytes' for larger values.
515+newtype Bytes = Bytes Int deriving (Eq, Read, Show, Generic, Typeable, Ord, ToJSON, FromJSON)
517+gigabytes :: Int -> Bytes
518+gigabytes n = megabytes (1000 * n)
521+megabytes :: Int -> Bytes
522+megabytes n = kilobytes (1000 * n)
525+kilobytes :: Int -> Bytes
526+kilobytes n = Bytes (1000 * n)
529+data FSType = FSSimple
530+ | FSBuffered deriving (Eq, Read, Show, Generic, Typeable, Ord)
532+data InitialShardCount = QuorumShards
533+ | QuorumMinus1Shards
536+ | ExplicitShards Int
537+ deriving (Eq, Read, Show, Generic, Typeable)
539+data NodeAttrFilter = NodeAttrFilter { nodeAttrFilterName :: NodeAttrName
540+ , nodeAttrFilterValues :: NonEmpty Text}
541+ deriving (Eq, Read, Show, Generic, Ord)
543+newtype NodeAttrName = NodeAttrName Text deriving (Eq, Read, Show, Ord, Generic, Typeable)
545+data CompoundFormat = CompoundFileFormat Bool
546+ | MergeSegmentVsTotalIndex Double
547+ -- ^ percentage between 0 and 1 where 0 is false, 1 is true
548+ deriving (Eq, Read, Show, Generic, Typeable)
550+newtype NominalDiffTimeJSON = NominalDiffTimeJSON { ndtJSON :: NominalDiffTime }
552+data IndexSettingsSummary = IndexSettingsSummary { sSummaryIndexName :: IndexName
553+ , sSummaryFixedSettings :: IndexSettings
554+ , sSummaryUpdateable :: [UpdatableIndexSetting]}
555+ deriving (Eq, Show, Generic, Typeable)
557+{-| 'Reply' and 'Method' are type synonyms from 'Network.HTTP.Types.Method.Method' -}
558+type Reply = Network.HTTP.Client.Response L.ByteString
559+type Method = NHTM.Method
561+{-| 'OpenCloseIndex' is a sum type for opening and closing indices.
563+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html>
565+data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Read, Show, Generic, Typeable)
567+data FieldType = GeoPointType
573+ | ByteType deriving (Eq, Read, Show, Generic, Typeable)
575+data FieldDefinition =
576+ FieldDefinition { fieldType :: FieldType } deriving (Eq, Read, Show, Generic, Typeable)
578+{-| An 'IndexTemplate' defines a template that will automatically be
579+ applied to new indices created. The templates include both
580+ 'IndexSettings' and mappings, and a simple 'TemplatePattern' that
581+ controls if the template will be applied to the index created.
582+ Specify mappings as follows: @[toJSON TweetMapping, ...]@
584+ https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
587+ IndexTemplate { templatePattern :: TemplatePattern
588+ , templateSettings :: Maybe IndexSettings
589+ , templateMappings :: [Value]
593+ MappingField { mappingFieldName :: FieldName
594+ , fieldDefinition :: FieldDefinition } deriving (Eq, Read, Show, Generic, Typeable)
596+{-| Support for type reification of 'Mapping's is currently incomplete, for
597+ now the mapping API verbiage expects a 'ToJSON'able blob.
599+ Indexes have mappings, mappings are schemas for the documents contained in the
600+ index. I'd recommend having only one mapping per index, always having a mapping,
601+ and keeping different kinds of documents separated if possible.
603+data Mapping = Mapping { typeName :: TypeName
604+ , mappingFields :: [MappingField] } deriving (Eq, Read, Show, Generic, Typeable)
606+{-| 'BulkOperation' is a sum type for expressing the four kinds of bulk
607+ operation index, create, delete, and update. 'BulkIndex' behaves like an
608+ "upsert", 'BulkCreate' will fail if a document already exists at the DocId.
610+ <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk>
613+ BulkIndex IndexName MappingName DocId Value
614+ | BulkCreate IndexName MappingName DocId Value
615+ | BulkDelete IndexName MappingName DocId
616+ | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Read, Show, Generic, Typeable)
618+{-| 'EsResult' describes the standard wrapper JSON document that you see in
619+ successful Elasticsearch lookups or lookups that couldn't find the document.
621+data EsResult a = EsResult { _index :: Text
624+ , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Read, Show, Generic, Typeable)
626+{-| 'EsResultFound' contains the document and its metadata inside of an
627+ 'EsResult' when the document was successfully found.
629+data EsResultFound a = EsResultFound { _version :: DocVersion
630+ , _source :: a } deriving (Eq, Read, Show, Generic, Typeable)
632+{-| 'EsError' is the generic type that will be returned when there was a
633+ problem. If you can't parse the expected response, its a good idea to
636+data EsError = EsError { errorStatus :: Int
637+ , errorMessage :: Text } deriving (Eq, Read, Show, Generic, Typeable)
639+{-| 'EsProtocolException' will be thrown if Bloodhound cannot parse a response
640+returned by the ElasticSearch server. If you encounter this error, please
641+verify that your domain data types and FromJSON instances are working properly
642+(for example, the 'a' of '[Hit a]' in 'SearchResult.searchHits.hits'). If you're
643+sure that your mappings are correct, then this error may be an indication of an
644+incompatibility between Bloodhound and ElasticSearch. Please open a bug report
645+and be sure to include the exception body.
647+data EsProtocolException = EsProtocolException { esProtoExBody :: L.ByteString }
648+ deriving (Eq, Read, Show, Generic, Typeable)
650+instance Exception EsProtocolException
652+data IndexAlias = IndexAlias { srcIndex :: IndexName
653+ , indexAlias :: IndexAliasName } deriving (Eq, Read, Show, Generic, Typeable)
655+newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Read, Show, Generic, ToJSON)
657+data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
658+ | RemoveAlias IndexAlias deriving (Read, Show, Eq, Generic, Typeable)
660+data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
661+ , aliasCreateFilter :: Maybe Filter}
662+ deriving (Read, Show, Eq, Generic, Typeable)
664+data AliasRouting = AllAliasRouting RoutingValue
665+ | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
666+ deriving (Read, Show, Eq, Generic, Typeable)
668+newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Read, Show, Eq, Generic, Typeable)
670+newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
672+newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Read, Show, Eq, Generic, ToJSON, FromJSON, Typeable)
674+newtype IndexAliasesSummary = IndexAliasesSummary { indexAliasesSummary :: [IndexAliasSummary] } deriving (Read, Show, Eq, Generic, Typeable)
676+{-| 'IndexAliasSummary' is a summary of an index alias configured for a server. -}
677+data IndexAliasSummary = IndexAliasSummary { indexAliasSummaryAlias :: IndexAlias
678+ , indexAliasSummaryCreate :: IndexAliasCreate} deriving (Read, Show, Eq, Generic, Typeable)
680+{-| 'DocVersion' is an integer version number for a document between 1
681+and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
683+newtype DocVersion = DocVersion {
684+ docVersionNumber :: Int
685+ } deriving (Eq, Read, Show, Generic, Ord, ToJSON)
687+-- | Smart constructor for in-range doc version
688+mkDocVersion :: Int -> Maybe DocVersion
690+ | i >= (docVersionNumber minBound) && i <= (docVersionNumber maxBound) =
692+ | otherwise = Nothing
695+{-| 'ExternalDocVersion' is a convenience wrapper if your code uses its
696+own version numbers instead of ones from ES.
698+newtype ExternalDocVersion = ExternalDocVersion DocVersion
699+ deriving (Eq, Read, Show, Generic, Ord, Bounded, Enum, ToJSON)
701+{-| 'VersionControl' is specified when indexing documents as a
702+optimistic concurrency control.
704+data VersionControl = NoVersionControl
705+ -- ^ Don't send a version. This is a pure overwrite.
706+ | InternalVersion DocVersion
707+ -- ^ Use the default ES versioning scheme. Only
708+ -- index the document if the version is the same
709+ -- as the one specified. Only applicable to
710+ -- updates, as you should be getting Version from
712+ | ExternalGT ExternalDocVersion
713+ -- ^ Use your own version numbering. Only index
714+ -- the document if the version is strictly higher
715+ -- OR the document doesn't exist. The given
716+ -- version will be used as the new version number
717+ -- for the stored document. N.B. All updates must
718+ -- increment this number, meaning there is some
719+ -- global, external ordering of updates.
720+ | ExternalGTE ExternalDocVersion
721+ -- ^ Use your own version numbering. Only index
722+ -- the document if the version is equal or higher
723+ -- than the stored version. Will succeed if there
724+ -- is no existing document. The given version will
725+ -- be used as the new version number for the
726+ -- stored document. Use with care, as this could
727+ -- result in data loss.
728+ | ForceVersion ExternalDocVersion
729+ -- ^ The document will always be indexed and the
730+ -- given version will be the new version. This is
731+ -- typically used for correcting errors. Use with
732+ -- care, as this could result in data loss.
733+ deriving (Read, Show, Eq, Generic, Ord)
735+{-| 'DocumentParent' is used to specify a parent document.
737+newtype DocumentParent = DocumentParent DocId
738+ deriving (Eq, Read, Show, Generic, Typeable)
740+{-| 'IndexDocumentSettings' are special settings supplied when indexing
741+a document. For the best backwards compatiblity when new fields are
742+added, you should probably prefer to start with 'defaultIndexDocumentSettings'
744+data IndexDocumentSettings =
745+ IndexDocumentSettings { idsVersionControl :: VersionControl
746+ , idsParent :: Maybe DocumentParent
747+ } deriving (Eq, Read, Show, Generic, Typeable)
749+{-| Reasonable default settings. Chooses no version control and no parent.
751+defaultIndexDocumentSettings :: IndexDocumentSettings
752+defaultIndexDocumentSettings = IndexDocumentSettings NoVersionControl Nothing
754+{-| 'Sort' is a synonym for a list of 'SortSpec's. Sort behavior is order
755+ dependent with later sorts acting as tie-breakers for earlier sorts.
757+type Sort = [SortSpec]
759+{-| The two main kinds of 'SortSpec' are 'DefaultSortSpec' and
760+ 'GeoDistanceSortSpec'. The latter takes a 'SortOrder', 'GeoPoint', and
761+ 'DistanceUnit' to express "nearness" to a single geographical point as a
764+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
766+data SortSpec = DefaultSortSpec DefaultSort
767+ | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Read, Show, Generic, Typeable)
769+{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
770+ 'mkSort' convenience function for when you want to specify only the most
773+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
776+ DefaultSort { sortFieldName :: FieldName
777+ , sortOrder :: SortOrder
779+ , ignoreUnmapped :: Bool
780+ , sortMode :: Maybe SortMode
781+ , missingSort :: Maybe Missing
782+ , nestedFilter :: Maybe Filter } deriving (Eq, Read, Show, Generic, Typeable)
784+{-| 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get
785+ encoded into "asc" or "desc" when turned into JSON.
787+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
789+data SortOrder = Ascending
790+ | Descending deriving (Eq, Read, Show, Generic, Typeable)
792+{-| 'Missing' prescribes how to handle missing fields. A missing field can be
793+ sorted last, first, or using a custom value as a substitute.
795+<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_missing_values>
797+data Missing = LastMissing
799+ | CustomMissing Text deriving (Eq, Read, Show, Generic, Typeable)
801+{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
803+http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
805+data SortMode = SortMin
808+ | SortAvg deriving (Eq, Read, Show, Generic, Typeable)
810+{-| 'mkSort' defaults everything but the 'FieldName' and the 'SortOrder' so
811+ that you can concisely describe the usual kind of 'SortSpec's you want.
813+mkSort :: FieldName -> SortOrder -> DefaultSort
814+mkSort fieldName sOrder = DefaultSort fieldName sOrder False Nothing Nothing Nothing
816+{-| 'Cache' is for telling ES whether it should cache a 'Filter' not.
817+ 'Query's cannot be cached.
819+type Cache = Bool -- caching on/off
820+defaultCache :: Cache
823+{-| 'PrefixValue' is used in 'PrefixQuery' as the main query component.
825+type PrefixValue = Text
827+{-| 'BooleanOperator' is the usual And/Or operators with an ES compatible
828+ JSON encoding baked in. Used all over the place.
830+data BooleanOperator = And | Or deriving (Eq, Read, Show, Generic, Typeable)
832+{-| 'ShardCount' is part of 'IndexSettings'
834+newtype ShardCount = ShardCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
836+{-| 'ReplicaCount' is part of 'IndexSettings'
838+newtype ReplicaCount = ReplicaCount Int deriving (Eq, Read, Show, Generic, ToJSON, Typeable)
840+{-| 'IndexName' is used to describe which index to query/create/delete
842+newtype IndexName = IndexName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
844+{-| 'IndexSelection' is used for APIs which take a single index, a list of
845+ indexes, or the special @_all@ index.
847+data IndexSelection = IndexList (NonEmpty IndexName)
848+ | AllIndexes deriving (Eq, Generic, Show, Typeable)
850+{-| 'TemplateName' is used to describe which template to query/create/delete
852+newtype TemplateName = TemplateName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
854+{-| 'TemplatePattern' represents a pattern which is matched against index names
856+newtype TemplatePattern = TemplatePattern Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
858+{-| 'MappingName' is part of mappings which are how ES describes and schematizes
859+ the data in the indices.
861+newtype MappingName = MappingName Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
863+{-| 'DocId' is a generic wrapper value for expressing unique Document IDs.
864+ Can be set by the user or created by ES itself. Often used in client
865+ functions for poking at specific documents.
867+newtype DocId = DocId Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
869+{-| 'QueryString' is used to wrap query text bodies, be they human written or not.
871+newtype QueryString = QueryString Text deriving (Eq, Generic, Read, Show, ToJSON, FromJSON, Typeable)
873+{-| 'FieldName' is used all over the place wherever a specific field within
874+ a document needs to be specified, usually in 'Query's or 'Filter's.
876+newtype FieldName = FieldName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
879+{-| 'Script' is often used in place of 'FieldName' to specify more
880+complex ways of extracting a value from a document.
882+newtype Script = Script { scriptText :: Text } deriving (Eq, Read, Show, Generic, Typeable)
884+{-| 'CacheName' is used in 'RegexpFilter' for describing the
885+ 'CacheKey' keyed caching behavior.
887+newtype CacheName = CacheName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
889+{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
892+ CacheKey Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
894+ Existence Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
896+ NullValue Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
897+newtype CutoffFrequency =
898+ CutoffFrequency Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
900+ Analyzer Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
901+newtype MaxExpansions =
902+ MaxExpansions Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
904+{-| 'Lenient', if set to true, will cause format based failures to be
905+ ignored. I don't know what the bloody default is, Elasticsearch
906+ documentation didn't say what it was. Let me know if you figure it out.
909+ Lenient Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
911+ Tiebreaker Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
913+ Boost Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
915+ BoostTerms Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
917+{-| 'MinimumMatch' controls how many should clauses in the bool query should
918+ match. Can be an absolute value (2) or a percentage (30%) or a
919+ combination of both.
921+newtype MinimumMatch =
922+ MinimumMatch Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
923+newtype DisableCoord =
924+ DisableCoord Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
925+newtype IgnoreTermFrequency =
926+ IgnoreTermFrequency Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
927+newtype MinimumTermFrequency =
928+ MinimumTermFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
929+newtype MaxQueryTerms =
930+ MaxQueryTerms Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
932+ Fuzziness Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
934+{-| 'PrefixLength' is the prefix length used in queries, defaults to 0. -}
935+newtype PrefixLength =
936+ PrefixLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
938+ TypeName Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
939+newtype PercentMatch =
940+ PercentMatch Double deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
942+ StopWord Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
944+ QueryPath Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
946+{-| Allowing a wildcard at the beginning of a word (eg "*ing") is particularly
947+ heavy, because all terms in the index need to be examined, just in case
948+ they match. Leading wildcards can be disabled by setting
949+ 'AllowLeadingWildcard' to false. -}
950+newtype AllowLeadingWildcard =
951+ AllowLeadingWildcard Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
952+newtype LowercaseExpanded =
953+ LowercaseExpanded Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
954+newtype EnablePositionIncrements =
955+ EnablePositionIncrements Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
957+{-| By default, wildcard terms in a query are not analyzed.
958+ Setting 'AnalyzeWildcard' to true enables best-effort analysis.
960+newtype AnalyzeWildcard = AnalyzeWildcard Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
962+{-| 'GeneratePhraseQueries' defaults to false.
964+newtype GeneratePhraseQueries =
965+ GeneratePhraseQueries Bool deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
967+{-| 'Locale' is used for string conversions - defaults to ROOT.
969+newtype Locale = Locale Text deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
970+newtype MaxWordLength = MaxWordLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
971+newtype MinWordLength = MinWordLength Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
973+{-| 'PhraseSlop' sets the default slop for phrases, 0 means exact
974+ phrase matches. Default is 0.
976+newtype PhraseSlop = PhraseSlop Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
977+newtype MinDocFrequency = MinDocFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
978+newtype MaxDocFrequency = MaxDocFrequency Int deriving (Eq, Read, Show, Generic, ToJSON, FromJSON, Typeable)
980+-- | Newtype wrapper to parse ES's concerning tendency to in some APIs return a floating point number of milliseconds since epoch ಠ_ಠ
981+newtype POSIXMS = POSIXMS { posixMS :: UTCTime }
430{-| 'unpackId' is a silly convenience function that gets used once.
983{-| 'unpackId' is a silly convenience function that gets used once.
@@ -433,6 +986,8 @@ unpackId :: DocId -> Text
433unpackId (DocId docId) = docId
986unpackId (DocId docId) = docId
435type TrackSortScores = Bool
988type TrackSortScores = Bool
989+newtype From = From Int deriving (Eq, Read, Show, Generic, ToJSON)
990+newtype Size = Size Int deriving (Eq, Read, Show, Generic, ToJSON)
437data Search = Search { queryBody :: Maybe Query
992data Search = Search { queryBody :: Maybe Query
438 , filterBody :: Maybe Filter
993 , filterBody :: Maybe Filter
@@ -444,74 +999,537 @@ data Search = Search { queryBody :: Maybe Query
444 , from :: From
999 , from :: From
445 , size :: Size
1000 , size :: Size
446 , searchType :: SearchType
1001 , searchType :: SearchType
447− , searchAfterKey :: Maybe SearchAfterKey
448 , fields :: Maybe [FieldName]
1002 , fields :: Maybe [FieldName]
449− , scriptFields :: Maybe ScriptFields
450− , source :: Maybe Source
1003+ , source :: Maybe Source } deriving (Eq, Read, Show, Generic, Typeable)
451− , suggestBody :: Maybe Suggest -- ^ Only one Suggestion request / response per Search is supported.
452− } deriving (Eq, Show)
455−instance ToJSON Search where
456− toJSON (Search mquery sFilter sort searchAggs
457− highlight sTrackSortScores sFrom sSize _ sAfter sFields
458− sScriptFields sSource sSuggest) =
459− omitNulls [ "query" .= query'
461− , "aggregations" .= searchAggs
462− , "highlight" .= highlight
465− , "track_scores" .= sTrackSortScores
466− , "search_after" .= sAfter
467− , "fields" .= sFields
468− , "script_fields" .= sScriptFields
469− , "_source" .= sSource
470− , "suggest" .= sSuggest]
472− where query' = case sFilter of
477− $ mkBoolQuery (maybeToList mquery)
480data SearchType = SearchTypeQueryThenFetch
1005data SearchType = SearchTypeQueryThenFetch
481 | SearchTypeDfsQueryThenFetch
1006 | SearchTypeDfsQueryThenFetch
1009+ | SearchTypeQueryAndFetch
1010+ | SearchTypeDfsQueryAndFetch
482− deriving (Eq, Show)
1011+ deriving (Eq, Read, Show, Generic, Typeable)
484data Source =
1013data Source =
485 NoSource
1014 NoSource
486 | SourcePatterns PatternOrPatterns
1015 | SourcePatterns PatternOrPatterns
487 | SourceIncludeExclude Include Exclude
1016 | SourceIncludeExclude Include Exclude
488− deriving (Eq, Show)
1017+ deriving (Read, Show, Eq, Generic, Typeable)
490−instance ToJSON Source where
491− toJSON NoSource = toJSON False
492− toJSON (SourcePatterns patterns) = toJSON patterns
493− toJSON (SourceIncludeExclude incl excl) = object [ "includes" .= incl, "excludes" .= excl ]
495data PatternOrPatterns = PopPattern Pattern
1019data PatternOrPatterns = PopPattern Pattern
496− | PopPatterns [Pattern] deriving (Eq, Read, Show)
1020+ | PopPatterns [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
498−instance ToJSON PatternOrPatterns where
1022+data Include = Include [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
499− toJSON (PopPattern pattern) = toJSON pattern
1023+data Exclude = Exclude [Pattern] deriving (Eq, Read, Show, Generic, Typeable)
500− toJSON (PopPatterns patterns) = toJSON patterns
502−data Include = Include [Pattern] deriving (Eq, Read, Show)
1025+newtype Pattern = Pattern Text deriving (Eq, Read, Show, Generic, Typeable)
503−data Exclude = Exclude [Pattern] deriving (Eq, Read, Show)
505−instance ToJSON Include where
1027+data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
506− toJSON (Include patterns) = toJSON patterns
1028+ , highlightFields :: [FieldHighlight]
1029+ } deriving (Read, Show, Eq, Generic, Typeable)
508−instance ToJSON Exclude where
1031+data FieldHighlight = FieldHighlight FieldName (Maybe HighlightSettings)
509− toJSON (Exclude patterns) = toJSON patterns
1032+ deriving (Read, Show, Eq, Generic, Typeable)
511−newtype Pattern = Pattern Text deriving (Eq, Read, Show)
513−instance ToJSON Pattern where
1035+data HighlightSettings = Plain PlainHighlight
514− toJSON (Pattern pattern) = toJSON pattern
1036+ | Postings PostingsHighlight
1037+ | FastVector FastVectorHighlight
1038+ deriving (Read, Show, Eq, Generic, Typeable)
1039+data PlainHighlight =
1040+ PlainHighlight { plainCommon :: Maybe CommonHighlight
1041+ , plainNonPost :: Maybe NonPostings } deriving (Read, Show, Eq, Generic, Typeable)
1043+ -- This requires that index_options are set to 'offset' in the mapping.
1044+data PostingsHighlight = PostingsHighlight (Maybe CommonHighlight) deriving (Read, Show, Eq, Generic, Typeable)
1046+-- This requires that term_vector is set to 'with_positions_offsets' in the mapping.
1047+data FastVectorHighlight =
1048+ FastVectorHighlight { fvCommon :: Maybe CommonHighlight
1049+ , fvNonPostSettings :: Maybe NonPostings
1050+ , boundaryChars :: Maybe Text
1051+ , boundaryMaxScan :: Maybe Int
1052+ , fragmentOffset :: Maybe Int
1053+ , matchedFields :: [Text]
1054+ , phraseLimit :: Maybe Int
1055+ } deriving (Read, Show, Eq, Generic, Typeable)
1057+data CommonHighlight =
1058+ CommonHighlight { order :: Maybe Text
1059+ , forceSource :: Maybe Bool
1060+ , tag :: Maybe HighlightTag
1061+ , encoder :: Maybe HighlightEncoder
1062+ , noMatchSize :: Maybe Int
1063+ , highlightQuery :: Maybe Query
1064+ , requireFieldMatch :: Maybe Bool
1065+ } deriving (Read, Show, Eq, Generic, Typeable)
1067+-- Settings that are only applicable to FastVector and Plain highlighters.
1069+ NonPostings { fragmentSize :: Maybe Int
1070+ , numberOfFragments :: Maybe Int} deriving (Read, Show, Eq, Generic, Typeable)
1072+data HighlightEncoder = DefaultEncoder
1074+ deriving (Read, Show, Eq, Generic, Typeable)
1076+-- NOTE: Should the tags use some kind of HTML type, rather than Text?
1077+data HighlightTag = TagSchema Text
1078+ | CustomTags ([Text], [Text]) -- Only uses more than the first value in the lists if fvh
1079+ deriving (Read, Show, Eq, Generic, Typeable)
1083+ TermQuery Term (Maybe Boost)
1084+ | TermsQuery Text (NonEmpty Text)
1085+ | QueryMatchQuery MatchQuery
1086+ | QueryMultiMatchQuery MultiMatchQuery
1087+ | QueryBoolQuery BoolQuery
1088+ | QueryBoostingQuery BoostingQuery
1089+ | QueryCommonTermsQuery CommonTermsQuery
1090+ | ConstantScoreFilter Filter Boost
1091+ | ConstantScoreQuery Query Boost
1092+ | QueryDisMaxQuery DisMaxQuery
1093+ | QueryFilteredQuery FilteredQuery
1094+ | QueryFuzzyLikeThisQuery FuzzyLikeThisQuery
1095+ | QueryFuzzyLikeFieldQuery FuzzyLikeFieldQuery
1096+ | QueryFuzzyQuery FuzzyQuery
1097+ | QueryHasChildQuery HasChildQuery
1098+ | QueryHasParentQuery HasParentQuery
1099+ | IdsQuery MappingName [DocId]
1100+ | QueryIndicesQuery IndicesQuery
1101+ | MatchAllQuery (Maybe Boost)
1102+ | QueryMoreLikeThisQuery MoreLikeThisQuery
1103+ | QueryMoreLikeThisFieldQuery MoreLikeThisFieldQuery
1104+ | QueryNestedQuery NestedQuery
1105+ | QueryPrefixQuery PrefixQuery
1106+ | QueryQueryStringQuery QueryStringQuery
1107+ | QuerySimpleQueryStringQuery SimpleQueryStringQuery
1108+ | QueryRangeQuery RangeQuery
1109+ | QueryRegexpQuery RegexpQuery
1110+ deriving (Eq, Read, Show, Generic, Typeable)
1113+ RegexpQuery { regexpQueryField :: FieldName
1114+ , regexpQuery :: Regexp
1115+ , regexpQueryFlags :: RegexpFlags
1116+ , regexpQueryBoost :: Maybe Boost
1117+ } deriving (Eq, Read, Show, Generic, Typeable)
1120+ RangeQuery { rangeQueryField :: FieldName
1121+ , rangeQueryRange :: RangeValue
1122+ , rangeQueryBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
1124+mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
1125+mkRangeQuery f r = RangeQuery f r (Boost 1.0)
1127+data SimpleQueryStringQuery =
1128+ SimpleQueryStringQuery
1129+ { simpleQueryStringQuery :: QueryString
1130+ , simpleQueryStringField :: Maybe FieldOrFields
1131+ , simpleQueryStringOperator :: Maybe BooleanOperator
1132+ , simpleQueryStringAnalyzer :: Maybe Analyzer
1133+ , simpleQueryStringFlags :: Maybe (NonEmpty SimpleQueryFlag)
1134+ , simpleQueryStringLowercaseExpanded :: Maybe LowercaseExpanded
1135+ , simpleQueryStringLocale :: Maybe Locale
1136+ } deriving (Eq, Read, Show, Generic, Typeable)
1138+data SimpleQueryFlag =
1143+ | SimpleQueryPrefix
1144+ | SimpleQueryPhrase
1145+ | SimpleQueryPrecedence
1146+ | SimpleQueryEscape
1147+ | SimpleQueryWhitespace
1150+ | SimpleQuerySlop deriving (Eq, Read, Show, Generic, Typeable)
1152+-- use_dis_max and tie_breaker when fields are plural?
1153+data QueryStringQuery =
1155+ { queryStringQuery :: QueryString
1156+ , queryStringDefaultField :: Maybe FieldName
1157+ , queryStringOperator :: Maybe BooleanOperator
1158+ , queryStringAnalyzer :: Maybe Analyzer
1159+ , queryStringAllowLeadingWildcard :: Maybe AllowLeadingWildcard
1160+ , queryStringLowercaseExpanded :: Maybe LowercaseExpanded
1161+ , queryStringEnablePositionIncrements :: Maybe EnablePositionIncrements
1162+ , queryStringFuzzyMaxExpansions :: Maybe MaxExpansions
1163+ , queryStringFuzziness :: Maybe Fuzziness
1164+ , queryStringFuzzyPrefixLength :: Maybe PrefixLength
1165+ , queryStringPhraseSlop :: Maybe PhraseSlop
1166+ , queryStringBoost :: Maybe Boost
1167+ , queryStringAnalyzeWildcard :: Maybe AnalyzeWildcard
1168+ , queryStringGeneratePhraseQueries :: Maybe GeneratePhraseQueries
1169+ , queryStringMinimumShouldMatch :: Maybe MinimumMatch
1170+ , queryStringLenient :: Maybe Lenient
1171+ , queryStringLocale :: Maybe Locale
1172+ } deriving (Eq, Read, Show, Generic, Typeable)
1174+mkQueryStringQuery :: QueryString -> QueryStringQuery
1175+mkQueryStringQuery qs =
1176+ QueryStringQuery qs Nothing Nothing
1177+ Nothing Nothing Nothing Nothing
1178+ Nothing Nothing Nothing Nothing
1179+ Nothing Nothing Nothing Nothing
1182+data FieldOrFields = FofField FieldName
1183+ | FofFields (NonEmpty FieldName) deriving (Eq, Read, Show, Generic, Typeable)
1187+ { prefixQueryField :: FieldName
1188+ , prefixQueryPrefixValue :: Text
1189+ , prefixQueryBoost :: Maybe Boost } deriving (Eq, Read, Show, Generic, Typeable)
1193+ { nestedQueryPath :: QueryPath
1194+ , nestedQueryScoreType :: ScoreType
1195+ , nestedQuery :: Query } deriving (Eq, Read, Show, Generic, Typeable)
1197+data MoreLikeThisFieldQuery =
1198+ MoreLikeThisFieldQuery
1199+ { moreLikeThisFieldText :: Text
1200+ , moreLikeThisFieldFields :: FieldName
1201+ -- default 0.3 (30%)
1202+ , moreLikeThisFieldPercentMatch :: Maybe PercentMatch
1203+ , moreLikeThisFieldMinimumTermFreq :: Maybe MinimumTermFrequency
1204+ , moreLikeThisFieldMaxQueryTerms :: Maybe MaxQueryTerms
1205+ , moreLikeThisFieldStopWords :: Maybe (NonEmpty StopWord)
1206+ , moreLikeThisFieldMinDocFrequency :: Maybe MinDocFrequency
1207+ , moreLikeThisFieldMaxDocFrequency :: Maybe MaxDocFrequency
1208+ , moreLikeThisFieldMinWordLength :: Maybe MinWordLength
1209+ , moreLikeThisFieldMaxWordLength :: Maybe MaxWordLength
1210+ , moreLikeThisFieldBoostTerms :: Maybe BoostTerms
1211+ , moreLikeThisFieldBoost :: Maybe Boost
1212+ , moreLikeThisFieldAnalyzer :: Maybe Analyzer
1213+ } deriving (Eq, Read, Show, Generic, Typeable)
1215+data MoreLikeThisQuery =
1217+ { moreLikeThisText :: Text
1218+ , moreLikeThisFields :: Maybe (NonEmpty FieldName)
1219+ -- default 0.3 (30%)
1220+ , moreLikeThisPercentMatch :: Maybe PercentMatch
1221+ , moreLikeThisMinimumTermFreq :: Maybe MinimumTermFrequency
1222+ , moreLikeThisMaxQueryTerms :: Maybe MaxQueryTerms
1223+ , moreLikeThisStopWords :: Maybe (NonEmpty StopWord)
1224+ , moreLikeThisMinDocFrequency :: Maybe MinDocFrequency
1225+ , moreLikeThisMaxDocFrequency :: Maybe MaxDocFrequency
1226+ , moreLikeThisMinWordLength :: Maybe MinWordLength
1227+ , moreLikeThisMaxWordLength :: Maybe MaxWordLength
1228+ , moreLikeThisBoostTerms :: Maybe BoostTerms
1229+ , moreLikeThisBoost :: Maybe Boost
1230+ , moreLikeThisAnalyzer :: Maybe Analyzer
1231+ } deriving (Eq, Read, Show, Generic, Typeable)
1235+ { indicesQueryIndices :: [IndexName]
1236+ , indicesQuery :: Query
1238+ , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Read, Show, Generic, Typeable)
1240+data HasParentQuery =
1242+ { hasParentQueryType :: TypeName
1243+ , hasParentQuery :: Query
1244+ , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1246+data HasChildQuery =
1248+ { hasChildQueryType :: TypeName
1249+ , hasChildQuery :: Query
1250+ , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Read, Show, Generic, Typeable)
1256+ | ScoreTypeNone deriving (Eq, Read, Show, Generic, Typeable)
1259+ FuzzyQuery { fuzzyQueryField :: FieldName
1260+ , fuzzyQueryValue :: Text
1261+ , fuzzyQueryPrefixLength :: PrefixLength
1262+ , fuzzyQueryMaxExpansions :: MaxExpansions
1263+ , fuzzyQueryFuzziness :: Fuzziness
1264+ , fuzzyQueryBoost :: Maybe Boost
1265+ } deriving (Eq, Read, Show, Generic, Typeable)
1267+data FuzzyLikeFieldQuery =
1268+ FuzzyLikeFieldQuery
1269+ { fuzzyLikeField :: FieldName
1270+ -- anaphora is good for the soul.
1271+ , fuzzyLikeFieldText :: Text
1272+ , fuzzyLikeFieldMaxQueryTerms :: MaxQueryTerms
1273+ , fuzzyLikeFieldIgnoreTermFrequency :: IgnoreTermFrequency
1274+ , fuzzyLikeFieldFuzziness :: Fuzziness
1275+ , fuzzyLikeFieldPrefixLength :: PrefixLength
1276+ , fuzzyLikeFieldBoost :: Boost
1277+ , fuzzyLikeFieldAnalyzer :: Maybe Analyzer
1278+ } deriving (Eq, Read, Show, Generic, Typeable)
1280+data FuzzyLikeThisQuery =
1282+ { fuzzyLikeFields :: [FieldName]
1283+ , fuzzyLikeText :: Text
1284+ , fuzzyLikeMaxQueryTerms :: MaxQueryTerms
1285+ , fuzzyLikeIgnoreTermFrequency :: IgnoreTermFrequency
1286+ , fuzzyLikeFuzziness :: Fuzziness
1287+ , fuzzyLikePrefixLength :: PrefixLength
1288+ , fuzzyLikeBoost :: Boost
1289+ , fuzzyLikeAnalyzer :: Maybe Analyzer
1290+ } deriving (Eq, Read, Show, Generic, Typeable)
1292+data FilteredQuery =
1294+ { filteredQuery :: Query
1295+ , filteredFilter :: Filter } deriving (Eq, Read, Show, Generic, Typeable)
1298+ DisMaxQuery { disMaxQueries :: [Query]
1300+ , disMaxTiebreaker :: Tiebreaker
1301+ , disMaxBoost :: Maybe Boost
1302+ } deriving (Eq, Read, Show, Generic, Typeable)
1305+ MatchQuery { matchQueryField :: FieldName
1306+ , matchQueryQueryString :: QueryString
1307+ , matchQueryOperator :: BooleanOperator
1308+ , matchQueryZeroTerms :: ZeroTermsQuery
1309+ , matchQueryCutoffFrequency :: Maybe CutoffFrequency
1310+ , matchQueryMatchType :: Maybe MatchQueryType
1311+ , matchQueryAnalyzer :: Maybe Analyzer
1312+ , matchQueryMaxExpansions :: Maybe MaxExpansions
1313+ , matchQueryLenient :: Maybe Lenient
1314+ , matchQueryBoost :: Maybe Boost } deriving (Eq, Read, Show, Generic, Typeable)
1316+{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
1317+ enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
1319+mkMatchQuery :: FieldName -> QueryString -> MatchQuery
1320+mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1322+data MatchQueryType =
1324+ | MatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
1326+data MultiMatchQuery =
1327+ MultiMatchQuery { multiMatchQueryFields :: [FieldName]
1328+ , multiMatchQueryString :: QueryString
1329+ , multiMatchQueryOperator :: BooleanOperator
1330+ , multiMatchQueryZeroTerms :: ZeroTermsQuery
1331+ , multiMatchQueryTiebreaker :: Maybe Tiebreaker
1332+ , multiMatchQueryType :: Maybe MultiMatchQueryType
1333+ , multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency
1334+ , multiMatchQueryAnalyzer :: Maybe Analyzer
1335+ , multiMatchQueryMaxExpansions :: Maybe MaxExpansions
1336+ , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Read, Show, Generic, Typeable)
1338+{-| 'mkMultiMatchQuery' is a convenience function that defaults the less common parameters,
1339+ enabling you to provide only the list of 'FieldName's and 'QueryString' to
1340+ make a 'MultiMatchQuery'.
1343+mkMultiMatchQuery :: [FieldName] -> QueryString -> MultiMatchQuery
1344+mkMultiMatchQuery matchFields query =
1345+ MultiMatchQuery matchFields query
1346+ Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1348+data MultiMatchQueryType =
1349+ MultiMatchBestFields
1350+ | MultiMatchMostFields
1351+ | MultiMatchCrossFields
1353+ | MultiMatchPhrasePrefix deriving (Eq, Read, Show, Generic, Typeable)
1356+ BoolQuery { boolQueryMustMatch :: [Query]
1357+ , boolQueryMustNotMatch :: [Query]
1358+ , boolQueryShouldMatch :: [Query]
1359+ , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
1360+ , boolQueryBoost :: Maybe Boost
1361+ , boolQueryDisableCoord :: Maybe DisableCoord
1362+ } deriving (Eq, Read, Show, Generic, Typeable)
1364+mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
1365+mkBoolQuery must mustNot should =
1366+ BoolQuery must mustNot should Nothing Nothing Nothing
1368+data BoostingQuery =
1369+ BoostingQuery { positiveQuery :: Query
1370+ , negativeQuery :: Query
1371+ , negativeBoost :: Boost } deriving (Eq, Read, Show, Generic, Typeable)
1373+data CommonTermsQuery =
1374+ CommonTermsQuery { commonField :: FieldName
1375+ , commonQuery :: QueryString
1376+ , commonCutoffFrequency :: CutoffFrequency
1377+ , commonLowFreqOperator :: BooleanOperator
1378+ , commonHighFreqOperator :: BooleanOperator
1379+ , commonMinimumShouldMatch :: Maybe CommonMinimumMatch
1380+ , commonBoost :: Maybe Boost
1381+ , commonAnalyzer :: Maybe Analyzer
1382+ , commonDisableCoord :: Maybe DisableCoord
1383+ } deriving (Eq, Read, Show, Generic, Typeable)
1385+data CommonMinimumMatch =
1386+ CommonMinimumMatchHighLow MinimumMatchHighLow
1387+ | CommonMinimumMatch MinimumMatch
1388+ deriving (Eq, Read, Show, Generic, Typeable)
1390+data MinimumMatchHighLow =
1391+ MinimumMatchHighLow { lowFreq :: MinimumMatch
1392+ , highFreq :: MinimumMatch } deriving (Eq, Read, Show, Generic, Typeable)
1394+data Filter = AndFilter [Filter] Cache
1395+ | OrFilter [Filter] Cache
1396+ | NotFilter Filter Cache
1398+ | BoolFilter BoolMatch
1399+ | ExistsFilter FieldName -- always cached
1400+ | GeoBoundingBoxFilter GeoBoundingBoxConstraint
1401+ | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
1402+ | GeoDistanceRangeFilter GeoPoint DistanceRange
1403+ | GeoPolygonFilter FieldName [LatLon]
1404+ | IdsFilter MappingName [DocId]
1406+ | MissingFilter FieldName Existence NullValue
1407+ | PrefixFilter FieldName PrefixValue Cache
1408+ | QueryFilter Query Cache
1409+ | RangeFilter FieldName RangeValue RangeExecution Cache
1410+ | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
1411+ | TermFilter Term Cache
1412+ deriving (Eq, Read, Show, Generic, Typeable)
1414+data ZeroTermsQuery = ZeroTermsNone
1415+ | ZeroTermsAll deriving (Eq, Read, Show, Generic, Typeable)
1417+data RangeExecution = RangeExecutionIndex
1418+ | RangeExecutionFielddata deriving (Eq, Read, Show, Generic, Typeable)
1420+newtype Regexp = Regexp Text deriving (Eq, Read, Show, Generic, Typeable, FromJSON)
1422+data RegexpFlags = AllRegexpFlags
1424+ | SomeRegexpFlags (NonEmpty RegexpFlag) deriving (Eq, Read, Show, Generic, Typeable)
1426+data RegexpFlag = AnyString
1431+ | Interval deriving (Eq, Read, Show, Generic, Typeable)
1433+newtype LessThan = LessThan Double deriving (Eq, Read, Show, Generic, Typeable)
1434+newtype LessThanEq = LessThanEq Double deriving (Eq, Read, Show, Generic, Typeable)
1435+newtype GreaterThan = GreaterThan Double deriving (Eq, Read, Show, Generic, Typeable)
1436+newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Read, Show, Generic, Typeable)
1438+newtype LessThanD = LessThanD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1439+newtype LessThanEqD = LessThanEqD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1440+newtype GreaterThanD = GreaterThanD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1441+newtype GreaterThanEqD = GreaterThanEqD UTCTime deriving (Eq, Read, Show, Generic, Typeable)
1443+data RangeValue = RangeDateLte LessThanEqD
1444+ | RangeDateLt LessThanD
1445+ | RangeDateGte GreaterThanEqD
1446+ | RangeDateGt GreaterThanD
1447+ | RangeDateGtLt GreaterThanD LessThanD
1448+ | RangeDateGteLte GreaterThanEqD LessThanEqD
1449+ | RangeDateGteLt GreaterThanEqD LessThanD
1450+ | RangeDateGtLte GreaterThanD LessThanEqD
1451+ | RangeDoubleLte LessThanEq
1452+ | RangeDoubleLt LessThan
1453+ | RangeDoubleGte GreaterThanEq
1454+ | RangeDoubleGt GreaterThan
1455+ | RangeDoubleGtLt GreaterThan LessThan
1456+ | RangeDoubleGteLte GreaterThanEq LessThanEq
1457+ | RangeDoubleGteLt GreaterThanEq LessThan
1458+ | RangeDoubleGtLte GreaterThan LessThanEq
1459+ deriving (Eq, Read, Show, Generic, Typeable)
1461+rangeValueToPair :: RangeValue -> [Pair]
1462+rangeValueToPair rv = case rv of
1463+ RangeDateLte (LessThanEqD t) -> ["lte" .= t]
1464+ RangeDateGte (GreaterThanEqD t) -> ["gte" .= t]
1465+ RangeDateLt (LessThanD t) -> ["lt" .= t]
1466+ RangeDateGt (GreaterThanD t) -> ["gt" .= t]
1467+ RangeDateGteLte (GreaterThanEqD l) (LessThanEqD g) -> ["gte" .= l, "lte" .= g]
1468+ RangeDateGtLte (GreaterThanD l) (LessThanEqD g) -> ["gt" .= l, "lte" .= g]
1469+ RangeDateGteLt (GreaterThanEqD l) (LessThanD g) -> ["gte" .= l, "lt" .= g]
1470+ RangeDateGtLt (GreaterThanD l) (LessThanD g) -> ["gt" .= l, "lt" .= g]
1471+ RangeDoubleLte (LessThanEq t) -> ["lte" .= t]
1472+ RangeDoubleGte (GreaterThanEq t) -> ["gte" .= t]
1473+ RangeDoubleLt (LessThan t) -> ["lt" .= t]
1474+ RangeDoubleGt (GreaterThan t) -> ["gt" .= t]
1475+ RangeDoubleGteLte (GreaterThanEq l) (LessThanEq g) -> ["gte" .= l, "lte" .= g]
1476+ RangeDoubleGtLte (GreaterThan l) (LessThanEq g) -> ["gt" .= l, "lte" .= g]
1477+ RangeDoubleGteLt (GreaterThanEq l) (LessThan g) -> ["gte" .= l, "lt" .= g]
1478+ RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g]
1480+data Term = Term { termField :: Text
1481+ , termValue :: Text } deriving (Eq, Read, Show, Generic, Typeable)
1483+data BoolMatch = MustMatch Term Cache
1484+ | MustNotMatch Term Cache
1485+ | ShouldMatch [Term] Cache deriving (Eq, Read, Show, Generic, Typeable)
1487+-- "memory" or "indexed"
1488+data GeoFilterType = GeoFilterMemory
1489+ | GeoFilterIndexed deriving (Eq, Read, Show, Generic, Typeable)
1491+data LatLon = LatLon { lat :: Double
1492+ , lon :: Double } deriving (Eq, Read, Show, Generic, Typeable)
1494+data GeoBoundingBox =
1495+ GeoBoundingBox { topLeft :: LatLon
1496+ , bottomRight :: LatLon } deriving (Eq, Read, Show, Generic, Typeable)
1498+data GeoBoundingBoxConstraint =
1499+ GeoBoundingBoxConstraint { geoBBField :: FieldName
1500+ , constraintBox :: GeoBoundingBox
1501+ , bbConstraintcache :: Cache
1502+ , geoType :: GeoFilterType
1503+ } deriving (Eq, Read, Show, Generic, Typeable)
1506+ GeoPoint { geoField :: FieldName
1507+ , latLon :: LatLon} deriving (Eq, Read, Show, Generic, Typeable)
1509+data DistanceUnit = Miles
1517+ | NauticalMiles deriving (Eq, Read, Show, Generic, Typeable)
1519+data DistanceType = Arc
1520+ | SloppyArc -- doesn't exist <1.0
1521+ | Plane deriving (Eq, Read, Show, Generic, Typeable)
1523+data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
1524+ | NoOptimizeBbox deriving (Eq, Read, Show, Generic, Typeable)
1527+ Distance { coefficient :: Double
1528+ , unit :: DistanceUnit } deriving (Eq, Read, Show, Generic, Typeable)
1530+data DistanceRange =
1531+ DistanceRange { distanceFrom :: Distance
1532+ , distanceTo :: Distance } deriving (Eq, Read, Show, Generic, Typeable)
516data SearchResult a =
1534data SearchResult a =
517 SearchResult { took :: Int
1535 SearchResult { took :: Int
@@ -519,24 +1537,2278 @@ data SearchResult a =
519 , shards :: ShardResult
1537 , shards :: ShardResult
520 , searchHits :: SearchHits a
1538 , searchHits :: SearchHits a
521 , aggregations :: Maybe AggregationResults
1539 , aggregations :: Maybe AggregationResults
522− , scrollId :: Maybe ScrollId
1540+ , scrollId :: Maybe ScrollId } deriving (Eq, Read, Show, Generic, Typeable)
523− -- ^ Only one Suggestion request / response per
1541+
524− -- Search is supported.
1542+newtype ScrollId = ScrollId Text deriving (Eq, Read, Show, Generic, Ord, ToJSON, FromJSON)
525− , suggest :: Maybe NamedSuggestionResponse
1543+
526− }
1544+type Score = Maybe Double
527− deriving (Eq, Show)
1545+
1547+ SearchHits { hitsTotal :: Int
1548+ , maxScore :: Score
1549+ , hits :: [Hit a] } deriving (Eq, Read, Show, Generic, Typeable)
1552+instance Monoid (SearchHits a) where
1553+ mempty = SearchHits 0 Nothing mempty
1554+ mappend (SearchHits ta ma ha) (SearchHits tb mb hb) =
1555+ SearchHits (ta + tb) (max ma mb) (ha <> hb)
1559+ Hit { hitIndex :: IndexName
1560+ , hitType :: MappingName
1561+ , hitDocId :: DocId
1562+ , hitScore :: Score
1563+ , hitSource :: Maybe a
1564+ , hitHighlight :: Maybe HitHighlight } deriving (Eq, Read, Show, Generic, Typeable)
1567+ ShardResult { shardTotal :: Int
1568+ , shardsSuccessful :: Int
1569+ , shardsFailed :: Int } deriving (Eq, Read, Show, Generic, Typeable)
1571+type HitHighlight = M.Map Text [Text]
1573+showText :: Show a => a -> Text
1574+showText = T.pack . show
1576+readMay :: Read a => String -> Maybe a
1577+readMay s = case reads s of
1578+ (a, ""):_ -> Just a
1581+parseReadText :: Read a => Text -> Parser a
1582+parseReadText = maybe mzero return . readMay . T.unpack
1584+type Aggregations = M.Map Text Aggregation
1586+emptyAggregations :: Aggregations
1587+emptyAggregations = M.empty
1589+mkAggregations :: Text -> Aggregation -> Aggregations
1590+mkAggregations name aggregation = M.insert name aggregation emptyAggregations
1592+data TermOrder = TermOrder{ termSortField :: Text
1593+ , termSortOrder :: SortOrder } deriving (Eq, Read, Show, Generic, Typeable)
1595+data TermInclusion = TermInclusion Text
1596+ | TermPattern Text Text deriving (Eq, Read, Show, Generic, Typeable)
1598+data CollectionMode = BreadthFirst
1599+ | DepthFirst deriving (Eq, Read, Show, Generic, Typeable)
1601+data ExecutionHint = Ordinals
1603+ | GlobalOrdinalsHash
1604+ | GlobalOrdinalsLowCardinality
1605+ | Map deriving (Eq, Read, Show, Generic, Typeable)
1607+data TimeInterval = Weeks
1611+ | Seconds deriving Eq
1613+data Interval = Year
1621+ | FractionalInterval Float TimeInterval deriving (Eq, Read, Show, Generic, Typeable)
1623+data Aggregation = TermsAgg TermsAggregation
1624+ | DateHistogramAgg DateHistogramAggregation
1625+ | ValueCountAgg ValueCountAggregation
1626+ | FilterAgg FilterAggregation
1627+ | DateRangeAgg DateRangeAggregation
1628+ | MissingAgg MissingAggregation deriving (Eq, Read, Show, Generic, Typeable)
1630+data MissingAggregation = MissingAggregation
1632+ } deriving (Eq, Read, Show, Generic, Typeable)
1634+data TermsAggregation = TermsAggregation { term :: Either Text Text
1635+ , termInclude :: Maybe TermInclusion
1636+ , termExclude :: Maybe TermInclusion
1637+ , termOrder :: Maybe TermOrder
1638+ , termMinDocCount :: Maybe Int
1639+ , termSize :: Maybe Int
1640+ , termShardSize :: Maybe Int
1641+ , termCollectMode :: Maybe CollectionMode
1642+ , termExecutionHint :: Maybe ExecutionHint
1643+ , termAggs :: Maybe Aggregations
1644+ } deriving (Eq, Read, Show, Generic, Typeable)
1646+data DateHistogramAggregation = DateHistogramAggregation { dateField :: FieldName
1647+ , dateInterval :: Interval
1648+ , dateFormat :: Maybe Text
1649+ -- pre and post deprecated in 1.5
1650+ , datePreZone :: Maybe Text
1651+ , datePostZone :: Maybe Text
1652+ , datePreOffset :: Maybe Text
1653+ , datePostOffset :: Maybe Text
1654+ , dateAggs :: Maybe Aggregations
1655+ } deriving (Eq, Read, Show, Generic, Typeable)
1658+data DateRangeAggregation = DateRangeAggregation { draField :: FieldName
1659+ , draFormat :: Maybe Text
1660+ , draRanges :: NonEmpty DateRangeAggRange
1661+ } deriving (Eq, Read, Show, Generic, Typeable)
1663+data DateRangeAggRange = DateRangeFrom DateMathExpr
1664+ | DateRangeTo DateMathExpr
1665+ | DateRangeFromAndTo DateMathExpr DateMathExpr deriving (Eq, Read, Show, Generic, Typeable)
1667+-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math> for more information.
1668+data DateMathExpr = DateMathExpr DateMathAnchor [DateMathModifier] deriving (Eq, Read, Show, Generic, Typeable)
1671+-- | Starting point for a date range. This along with the 'DateMathModifiers' gets you the date ES will start from.
1672+data DateMathAnchor = DMNow
1673+ | DMDate Day deriving (Eq, Read, Show, Generic, Typeable)
1675+data DateMathModifier = AddTime Int DateMathUnit
1676+ | SubtractTime Int DateMathUnit
1677+ | RoundDownTo DateMathUnit deriving (Eq, Read, Show, Generic, Typeable)
1679+data DateMathUnit = DMYear
1685+ | DMSecond deriving (Eq, Read, Show, Generic, Typeable)
1687+-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-valuecount-aggregation.html> for more information.
1688+data ValueCountAggregation = FieldValueCount FieldName
1689+ | ScriptValueCount Script deriving (Eq, Read, Show, Generic, Typeable)
1691+-- | 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.
1692+data FilterAggregation = FilterAggregation { faFilter :: Filter
1693+ , faAggs :: Maybe Aggregations} deriving (Eq, Read, Show, Generic, Typeable)
1695+mkTermsAggregation :: Text -> TermsAggregation
1696+mkTermsAggregation t = TermsAggregation (Left t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1698+mkTermsScriptAggregation :: Text -> TermsAggregation
1699+mkTermsScriptAggregation t = TermsAggregation (Right t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1701+mkDateHistogram :: FieldName -> Interval -> DateHistogramAggregation
1702+mkDateHistogram t i = DateHistogramAggregation t i Nothing Nothing Nothing Nothing Nothing Nothing
1704+instance ToJSON Version where
1705+ toJSON Version {..} = object ["number" .= number
1706+ ,"build_hash" .= build_hash
1707+ ,"build_timestamp" .= build_timestamp
1708+ ,"build_snapshot" .= build_snapshot
1709+ ,"lucene_version" .= lucene_version]
1711+instance FromJSON Version where
1712+ parseJSON = withObject "Version" parse
1713+ where parse o = Version
1715+ <*> o .: "build_hash"
1716+ <*> o .: "build_timestamp"
1717+ <*> o .: "build_snapshot"
1718+ <*> o .: "lucene_version"
1720+instance ToJSON TermOrder where
1721+ toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
1723+instance ToJSON TermInclusion where
1724+ toJSON (TermInclusion x) = toJSON x
1725+ toJSON (TermPattern pattern flags) = omitNulls [ "pattern" .= pattern,
1728+instance ToJSON CollectionMode where
1729+ toJSON BreadthFirst = "breadth_first"
1730+ toJSON DepthFirst = "depth_first"
1732+instance ToJSON ExecutionHint where
1733+ toJSON Ordinals = "ordinals"
1734+ toJSON GlobalOrdinals = "global_ordinals"
1735+ toJSON GlobalOrdinalsHash = "global_ordinals_hash"
1736+ toJSON GlobalOrdinalsLowCardinality = "global_ordinals_low_cardinality"
1739+instance ToJSON Interval where
1740+ toJSON Year = "year"
1741+ toJSON Quarter = "quarter"
1742+ toJSON Month = "month"
1743+ toJSON Week = "week"
1745+ toJSON Hour = "hour"
1746+ toJSON Minute = "minute"
1747+ toJSON Second = "second"
1748+ toJSON (FractionalInterval fraction interval) = toJSON $ show fraction ++ show interval
1750+instance Show TimeInterval where
1757+instance Read TimeInterval where
1758+ readPrec = f =<< TR.get
1760+ f 'w' = return Weeks
1761+ f 'd' = return Days
1762+ f 'h' = return Hours
1763+ f 'm' = return Minutes
1764+ f 's' = return Seconds
1765+ f _ = fail "TimeInterval expected one of w, d, h, m, s"
1767+instance ToJSON Aggregation where
1768+ toJSON (TermsAgg (TermsAggregation term include exclude order minDocCount size shardSize collectMode executionHint termAggs)) =
1769+ omitNulls ["terms" .= omitNulls [ toJSON' term,
1770+ "include" .= include,
1771+ "exclude" .= exclude,
1773+ "min_doc_count" .= minDocCount,
1775+ "shard_size" .= shardSize,
1776+ "collect_mode" .= collectMode,
1777+ "execution_hint" .= executionHint
1779+ "aggs" .= termAggs ]
1781+ toJSON' x = case x of { Left y -> "field" .= y; Right y -> "script" .= y }
1783+ toJSON (DateHistogramAgg (DateHistogramAggregation field interval format preZone postZone preOffset postOffset dateHistoAggs)) =
1784+ omitNulls ["date_histogram" .= omitNulls [ "field" .= field,
1785+ "interval" .= interval,
1786+ "format" .= format,
1787+ "pre_zone" .= preZone,
1788+ "post_zone" .= postZone,
1789+ "pre_offset" .= preOffset,
1790+ "post_offset" .= postOffset
1792+ "aggs" .= dateHistoAggs ]
1793+ toJSON (ValueCountAgg a) = object ["value_count" .= v]
1794+ where v = case a of
1795+ (FieldValueCount (FieldName n)) -> object ["field" .= n]
1796+ (ScriptValueCount (Script s)) -> object ["script" .= s]
1797+ toJSON (FilterAgg (FilterAggregation filt ags)) =
1798+ omitNulls [ "filter" .= filt
1800+ toJSON (DateRangeAgg a) = object [ "date_range" .= a
1802+ toJSON (MissingAgg (MissingAggregation{..})) =
1803+ object ["missing" .= object ["field" .= maField]]
1805+instance ToJSON DateRangeAggregation where
1806+ toJSON DateRangeAggregation {..} =
1807+ omitNulls [ "field" .= draField
1808+ , "format" .= draFormat
1809+ , "ranges" .= toList draRanges
1812+instance ToJSON DateRangeAggRange where
1813+ toJSON (DateRangeFrom e) = object [ "from" .= e ]
1814+ toJSON (DateRangeTo e) = object [ "to" .= e ]
1815+ toJSON (DateRangeFromAndTo f t) = object [ "from" .= f, "to" .= t ]
1817+instance ToJSON DateMathExpr where
1818+ toJSON (DateMathExpr a mods) = String (fmtA a <> mconcat (fmtMod <$> mods))
1819+ where fmtA DMNow = "now"
1820+ fmtA (DMDate date) = case toGregorian date of
1821+ (y,m,d) -> showText y <> "-" <>
1822+ showText m <> "-" <>
1824+ fmtMod (AddTime n u) = "+" <> showText n <> fmtU u
1825+ fmtMod (SubtractTime n u) = "-" <> showText n <> fmtU u
1826+ fmtMod (RoundDownTo u) = "/" <> fmtU u
1832+ fmtU DMMinute = "m"
1833+ fmtU DMSecond = "s"
1836+type AggregationResults = M.Map Text Value
1838+class BucketAggregation a where
1839+ key :: a -> BucketValue
1840+ docCount :: a -> Int
1841+ aggs :: a -> Maybe AggregationResults
1844+data Bucket a = Bucket { buckets :: [a]} deriving (Read, Show)
1846+data BucketValue = TextValue Text
1847+ | ScientificValue Scientific
1848+ | BoolValue Bool deriving (Read, Show)
1850+data MissingResult = MissingResult { missingDocCount :: Int } deriving (Show)
1852+data TermsResult = TermsResult { termKey :: BucketValue
1853+ , termsDocCount :: Int
1854+ , termsAggs :: Maybe AggregationResults } deriving (Read, Show)
1856+data DateHistogramResult = DateHistogramResult { dateKey :: Int
1857+ , dateKeyStr :: Maybe Text
1858+ , dateDocCount :: Int
1859+ , dateHistogramAggs :: Maybe AggregationResults } deriving (Read, Show)
1861+data DateRangeResult = DateRangeResult { dateRangeKey :: Text
1862+ , dateRangeFrom :: Maybe UTCTime
1863+ , dateRangeFromAsString :: Maybe Text
1864+ , dateRangeTo :: Maybe UTCTime
1865+ , dateRangeToAsString :: Maybe Text
1866+ , dateRangeDocCount :: Int
1867+ , dateRangeAggs :: Maybe AggregationResults } deriving (Read, Show, Eq, Generic, Typeable)
1869+toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
1870+toTerms = toAggResult
1872+toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
1873+toDateHistogram = toAggResult
1875+toMissing :: Text -> AggregationResults -> Maybe MissingResult
1876+toMissing = toAggResult
1878+toAggResult :: (FromJSON a) => Text -> AggregationResults -> Maybe a
1879+toAggResult t a = M.lookup t a >>= deserialize
1880+ where deserialize = parseMaybe parseJSON
1882+instance BucketAggregation TermsResult where
1884+ docCount = termsDocCount
1887+instance BucketAggregation DateHistogramResult where
1888+ key = TextValue . showText . dateKey
1889+ docCount = dateDocCount
1890+ aggs = dateHistogramAggs
1892+instance BucketAggregation DateRangeResult where
1893+ key = TextValue . dateRangeKey
1894+ docCount = dateRangeDocCount
1895+ aggs = dateRangeAggs
1897+instance (FromJSON a, BucketAggregation a) => FromJSON (Bucket a) where
1898+ parseJSON (Object v) = Bucket <$>
1900+ parseJSON _ = mempty
1902+instance FromJSON BucketValue where
1903+ parseJSON (String t) = return $ TextValue t
1904+ parseJSON (Number s) = return $ ScientificValue s
1905+ parseJSON (Bool b) = return $ BoolValue b
1906+ parseJSON _ = mempty
1908+instance FromJSON MissingResult where
1909+ parseJSON = withObject "MissingResult" parse
1910+ where parse v = MissingResult <$> v .: "doc_count"
1912+instance FromJSON TermsResult where
1913+ parseJSON (Object v) = TermsResult <$>
1915+ v .: "doc_count" <*>
1916+ v .:? "aggregations"
1917+ parseJSON _ = mempty
1919+instance FromJSON DateHistogramResult where
1920+ parseJSON (Object v) = DateHistogramResult <$>
1922+ v .:? "key_as_string" <*>
1923+ v .: "doc_count" <*>
1924+ v .:? "aggregations"
1925+ parseJSON _ = mempty
1927+instance FromJSON DateRangeResult where
1928+ parseJSON = withObject "DateRangeResult" parse
1929+ where parse v = DateRangeResult <$>
1931+ (fmap posixMS <$> v .:? "from") <*>
1932+ v .:? "from_as_string" <*>
1933+ (fmap posixMS <$> v .:? "to") <*>
1934+ v .:? "to_as_string" <*>
1935+ v .: "doc_count" <*>
1936+ v .:? "aggregations"
1938+instance FromJSON POSIXMS where
1939+ parseJSON = withScientific "POSIXMS" (return . parse)
1940+ where parse n = let n' = truncate n :: Integer
1941+ in POSIXMS (posixSecondsToUTCTime (fromInteger (n' `div` 1000)))
1943+instance Monoid Filter where
1944+ mempty = IdentityFilter
1945+ mappend a b = AndFilter [a, b] defaultCache
1947+instance Seminearring Filter where
1948+ a <||> b = OrFilter [a, b] defaultCache
1950+instance ToJSON Filter where
1951+ toJSON (AndFilter filters cache) =
1953+ object [ "filters" .= fmap toJSON filters
1954+ , "_cache" .= cache]]
1956+ toJSON (OrFilter filters cache) =
1958+ object [ "filters" .= fmap toJSON filters
1959+ , "_cache" .= cache]]
1961+ toJSON (NotFilter notFilter cache) =
1963+ object ["filter" .= notFilter
1964+ , "_cache" .= cache]]
1966+ toJSON (IdentityFilter) =
1967+ object ["match_all" .= object []]
1969+ toJSON (TermFilter (Term termFilterField termFilterValue) cache) =
1970+ object ["term" .= object base]
1971+ where base = [termFilterField .= termFilterValue,
1974+ toJSON (ExistsFilter (FieldName fieldName)) =
1975+ object ["exists" .= object
1976+ ["field" .= fieldName]]
1978+ toJSON (BoolFilter boolMatch) =
1979+ object ["bool" .= boolMatch]
1981+ toJSON (GeoBoundingBoxFilter bbConstraint) =
1982+ object ["geo_bounding_box" .= bbConstraint]
1984+ toJSON (GeoDistanceFilter (GeoPoint (FieldName distanceGeoField) geoDistLatLon)
1985+ distance distanceType optimizeBbox cache) =
1986+ object ["geo_distance" .=
1987+ object ["distance" .= distance
1988+ , "distance_type" .= distanceType
1989+ , "optimize_bbox" .= optimizeBbox
1990+ , distanceGeoField .= geoDistLatLon
1991+ , "_cache" .= cache]]
1993+ toJSON (GeoDistanceRangeFilter (GeoPoint (FieldName gddrField) drLatLon)
1994+ (DistanceRange geoDistRangeDistFrom drDistanceTo)) =
1995+ object ["geo_distance_range" .=
1996+ object ["from" .= geoDistRangeDistFrom
1997+ , "to" .= drDistanceTo
1998+ , gddrField .= drLatLon]]
2000+ toJSON (GeoPolygonFilter (FieldName geoPolygonFilterField) latLons) =
2001+ object ["geo_polygon" .=
2002+ object [geoPolygonFilterField .=
2003+ object ["points" .= fmap toJSON latLons]]]
2005+ toJSON (IdsFilter (MappingName mappingName) values) =
2007+ object ["type" .= mappingName
2008+ , "values" .= fmap unpackId values]]
2010+ toJSON (LimitFilter limit) =
2011+ object ["limit" .= object ["value" .= limit]]
2013+ toJSON (MissingFilter (FieldName fieldName) (Existence existence) (NullValue nullValue)) =
2014+ object ["missing" .=
2015+ object ["field" .= fieldName
2016+ , "existence" .= existence
2017+ , "null_value" .= nullValue]]
2019+ toJSON (PrefixFilter (FieldName fieldName) fieldValue cache) =
2020+ object ["prefix" .=
2021+ object [fieldName .= fieldValue
2022+ , "_cache" .= cache]]
2024+ toJSON (QueryFilter query False) =
2025+ object ["query" .= toJSON query ]
2026+ toJSON (QueryFilter query True) =
2027+ object ["fquery" .=
2028+ object [ "query" .= toJSON query
2029+ , "_cache" .= True ]]
2031+ toJSON (RangeFilter (FieldName fieldName) rangeValue rangeExecution cache) =
2033+ object [ fieldName .= object (rangeValueToPair rangeValue)
2034+ , "execution" .= rangeExecution
2035+ , "_cache" .= cache]]
2037+ toJSON (RegexpFilter (FieldName fieldName)
2038+ (Regexp regexText) flags (CacheName cacheName) cache (CacheKey cacheKey)) =
2039+ object ["regexp" .=
2040+ object [fieldName .=
2041+ object ["value" .= regexText
2042+ , "flags" .= flags]
2043+ , "_name" .= cacheName
2044+ , "_cache" .= cache
2045+ , "_cache_key" .= cacheKey]]
2047+instance FromJSON Filter where
2048+ parseJSON = withObject "Filter" parse
2049+ where parse o = andFilter `taggedWith` "and"
2050+ <|> orFilter `taggedWith` "or"
2051+ <|> notFilter `taggedWith` "not"
2052+ <|> identityFilter `taggedWith` "match_all"
2053+ <|> boolFilter `taggedWith` "bool"
2054+ <|> existsFilter `taggedWith` "exists"
2055+ <|> geoBoundingBoxFilter `taggedWith` "geo_bounding_box"
2056+ <|> geoDistanceFilter `taggedWith` "geo_distance"
2057+ <|> geoDistanceRangeFilter `taggedWith` "geo_distance_range"
2058+ <|> geoPolygonFilter `taggedWith` "geo_polygon"
2059+ <|> idsFilter `taggedWith` "ids"
2060+ <|> limitFilter `taggedWith` "limit"
2061+ <|> missingFilter `taggedWith` "missing"
2062+ <|> prefixFilter `taggedWith` "prefix"
2063+ <|> queryFilter `taggedWith` "query"
2064+ <|> fqueryFilter `taggedWith` "fquery"
2065+ <|> rangeFilter `taggedWith` "range"
2066+ <|> regexpFilter `taggedWith` "regexp"
2067+ <|> termFilter `taggedWith` "term"
2068+ where taggedWith parser k = parser =<< o .: k
2069+ andFilter o = AndFilter <$> o .: "filters"
2070+ <*> o .:? "_cache" .!= defaultCache
2071+ orFilter o = OrFilter <$> o .: "filters"
2072+ <*> o .:? "_cache" .!= defaultCache
2073+ notFilter o = NotFilter <$> o .: "filter"
2074+ <*> o .: "_cache" .!= defaultCache
2075+ identityFilter :: Object -> Parser Filter
2077+ | HM.null m = pure IdentityFilter
2078+ | otherwise = fail ("Identityfilter expected empty object but got " <> show m)
2079+ boolFilter = pure . BoolFilter
2080+ existsFilter o = ExistsFilter <$> o .: "field"
2081+ geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
2082+ geoDistanceFilter o = do
2083+ case HM.toList (deleteSeveral ["distance", "distance_type", "optimize_bbox", "_cache"] o) of
2085+ gp <- GeoPoint (FieldName fn) <$> parseJSON v
2086+ GeoDistanceFilter gp <$> o .: "distance"
2087+ <*> o .: "distance_type"
2088+ <*> o .: "optimize_bbox"
2089+ <*> o .:? "_cache" .!= defaultCache
2090+ _ -> fail "Could not find GeoDistanceFilter field name"
2091+ geoDistanceRangeFilter o = do
2092+ case HM.toList (deleteSeveral ["from", "to"] o) of
2094+ gp <- GeoPoint (FieldName fn) <$> parseJSON v
2095+ rng <- DistanceRange <$> o .: "from" <*> o .: "to"
2096+ return (GeoDistanceRangeFilter gp rng)
2097+ _ -> fail "Could not find GeoDistanceRangeFilter field name"
2098+ geoPolygonFilter = fieldTagged $ \fn o -> GeoPolygonFilter fn <$> o .: "points"
2099+ idsFilter o = IdsFilter <$> o .: "type"
2101+ limitFilter o = LimitFilter <$> o .: "value"
2102+ missingFilter o = MissingFilter <$> o .: "field"
2103+ <*> o .: "existence"
2104+ <*> o .: "null_value"
2105+ prefixFilter o = case HM.toList (HM.delete "_cache" o) of
2106+ [(fn, String v)] -> PrefixFilter (FieldName fn) v <$> o .:? "_cache" .!= defaultCache
2107+ _ -> fail "Could not parse PrefixFilter"
2109+ queryFilter q = pure (QueryFilter q False)
2110+ fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
2111+ rangeFilter o = case HM.toList (deleteSeveral ["execution", "_cache"] o) of
2112+ [(fn, v)] -> RangeFilter (FieldName fn)
2114+ <*> o .: "execution"
2115+ <*> o .:? "_cache" .!= defaultCache
2116+ _ -> fail "Could not find field name for RangeFilter"
2117+ regexpFilter o = case HM.toList (deleteSeveral ["_name", "_cache", "_cache_key"] o) of
2118+ [(fn, Object o')] -> RegexpFilter (FieldName fn)
2122+ <*> o .:? "_cache" .!= defaultCache
2123+ <*> o .: "_cache_key"
2124+ _ -> fail "Could not find field name for RegexpFilter"
2125+ termFilter o = case HM.toList (HM.delete "_cache" o) of
2126+ [(termField, String termVal)] -> TermFilter (Term termField termVal)
2127+ <$> o .:? "_cache" .!= defaultCache
2128+ _ -> fail "Could not find term field for TermFilter"
2130+fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
2131+fieldTagged f o = case HM.toList o of
2132+ [(k, Object o')] -> f (FieldName k) o'
2133+ _ -> fail "Expected object with 1 field-named key"
2135+instance ToJSON GeoPoint where
2136+ toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
2137+ object [ geoPointField .= geoPointLatLon ]
2140+instance ToJSON Query where
2141+ toJSON (TermQuery (Term termQueryField termQueryValue) boost) =
2143+ object [termQueryField .= object merged]]
2145+ base = [ "value" .= termQueryValue ]
2146+ boosted = maybe [] (return . ("boost" .=)) boost
2147+ merged = mappend base boosted
2149+ toJSON (TermsQuery fieldName terms) =
2150+ object [ "terms" .= object conjoined ]
2151+ where conjoined = [fieldName .= terms]
2153+ toJSON (IdsQuery idsQueryMappingName docIds) =
2154+ object [ "ids" .= object conjoined ]
2155+ where conjoined = [ "type" .= idsQueryMappingName
2156+ , "values" .= fmap toJSON docIds ]
2158+ toJSON (QueryQueryStringQuery qQueryStringQuery) =
2159+ object [ "query_string" .= qQueryStringQuery ]
2161+ toJSON (QueryMatchQuery matchQuery) =
2162+ object [ "match" .= matchQuery ]
2164+ toJSON (QueryMultiMatchQuery multiMatchQuery) =
2165+ toJSON multiMatchQuery
2167+ toJSON (QueryBoolQuery boolQuery) =
2168+ object [ "bool" .= boolQuery ]
2170+ toJSON (QueryBoostingQuery boostingQuery) =
2171+ object [ "boosting" .= boostingQuery ]
2173+ toJSON (QueryCommonTermsQuery commonTermsQuery) =
2174+ object [ "common" .= commonTermsQuery ]
2176+ toJSON (ConstantScoreFilter csFilter boost) =
2177+ object ["constant_score" .= object ["filter" .= csFilter
2178+ , "boost" .= boost]]
2180+ toJSON (ConstantScoreQuery query boost) =
2181+ object ["constant_score" .= object ["query" .= query
2182+ , "boost" .= boost]]
2184+ toJSON (QueryDisMaxQuery disMaxQuery) =
2185+ object [ "dis_max" .= disMaxQuery ]
2187+ toJSON (QueryFilteredQuery qFilteredQuery) =
2188+ object [ "filtered" .= qFilteredQuery ]
2190+ toJSON (QueryFuzzyLikeThisQuery fuzzyQuery) =
2191+ object [ "fuzzy_like_this" .= fuzzyQuery ]
2193+ toJSON (QueryFuzzyLikeFieldQuery fuzzyFieldQuery) =
2194+ object [ "fuzzy_like_this_field" .= fuzzyFieldQuery ]
2196+ toJSON (QueryFuzzyQuery fuzzyQuery) =
2197+ object [ "fuzzy" .= fuzzyQuery ]
2199+ toJSON (QueryHasChildQuery childQuery) =
2200+ object [ "has_child" .= childQuery ]
2202+ toJSON (QueryHasParentQuery parentQuery) =
2203+ object [ "has_parent" .= parentQuery ]
2205+ toJSON (QueryIndicesQuery qIndicesQuery) =
2206+ object [ "indices" .= qIndicesQuery ]
2208+ toJSON (MatchAllQuery boost) =
2209+ object [ "match_all" .= omitNulls [ "boost" .= boost ] ]
2211+ toJSON (QueryMoreLikeThisQuery query) =
2212+ object [ "more_like_this" .= query ]
2214+ toJSON (QueryMoreLikeThisFieldQuery query) =
2215+ object [ "more_like_this_field" .= query ]
2217+ toJSON (QueryNestedQuery query) =
2218+ object [ "nested" .= query ]
2220+ toJSON (QueryPrefixQuery query) =
2221+ object [ "prefix" .= query ]
2223+ toJSON (QueryRangeQuery query) =
2224+ object [ "range" .= query ]
2226+ toJSON (QueryRegexpQuery query) =
2227+ object [ "regexp" .= query ]
2229+ toJSON (QuerySimpleQueryStringQuery query) =
2230+ object [ "simple_query_string" .= query ]
2232+instance FromJSON Query where
2233+ parseJSON v = withObject "Query" parse v
2234+ where parse o = termQuery `taggedWith` "term"
2235+ <|> termsQuery `taggedWith` "terms"
2236+ <|> idsQuery `taggedWith` "ids"
2237+ <|> queryQueryStringQuery `taggedWith` "query_string"
2238+ <|> queryMatchQuery `taggedWith` "match"
2239+ <|> queryMultiMatchQuery
2240+ <|> queryBoolQuery `taggedWith` "bool"
2241+ <|> queryBoostingQuery `taggedWith` "boosting"
2242+ <|> queryCommonTermsQuery `taggedWith` "common"
2243+ <|> constantScoreFilter `taggedWith` "constant_score"
2244+ <|> constantScoreQuery `taggedWith` "constant_score"
2245+ <|> queryDisMaxQuery `taggedWith` "dis_max"
2246+ <|> queryFilteredQuery `taggedWith` "filtered"
2247+ <|> queryFuzzyLikeThisQuery `taggedWith` "fuzzy_like_this"
2248+ <|> queryFuzzyLikeFieldQuery `taggedWith` "fuzzy_like_this_field"
2249+ <|> queryFuzzyQuery `taggedWith` "fuzzy"
2250+ <|> queryHasChildQuery `taggedWith` "has_child"
2251+ <|> queryHasParentQuery `taggedWith` "has_parent"
2252+ <|> queryIndicesQuery `taggedWith` "indices"
2253+ <|> matchAllQuery `taggedWith` "match_all"
2254+ <|> queryMoreLikeThisQuery `taggedWith` "more_like_this"
2255+ <|> queryMoreLikeThisFieldQuery `taggedWith` "more_like_this_field"
2256+ <|> queryNestedQuery `taggedWith` "nested"
2257+ <|> queryPrefixQuery `taggedWith` "prefix"
2258+ <|> queryRangeQuery `taggedWith` "range"
2259+ <|> queryRegexpQuery `taggedWith` "regexp"
2260+ <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
2261+ where taggedWith parser k = parser =<< o .: k
2262+ termQuery = fieldTagged $ \(FieldName fn) o ->
2263+ TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
2264+ termsQuery o = case HM.toList o of
2265+ [(fn, vs)] -> do vals <- parseJSON vs
2267+ x:xs -> return (TermsQuery fn (x :| xs))
2268+ _ -> fail "Expected non empty list of values"
2269+ _ -> fail "Expected object with 1 field-named key"
2270+ idsQuery o = IdsQuery <$> o .: "type"
2272+ queryQueryStringQuery = pure . QueryQueryStringQuery
2273+ queryMatchQuery = pure . QueryMatchQuery
2274+ queryMultiMatchQuery = QueryMultiMatchQuery <$> parseJSON v
2275+ queryBoolQuery = pure . QueryBoolQuery
2276+ queryBoostingQuery = pure . QueryBoostingQuery
2277+ queryCommonTermsQuery = pure . QueryCommonTermsQuery
2278+ constantScoreFilter o = case HM.lookup "filter" o of
2279+ Just x -> ConstantScoreFilter <$> parseJSON x
2281+ _ -> fail "Does not appear to be a ConstantScoreFilter"
2282+ constantScoreQuery o = case HM.lookup "query" o of
2283+ Just x -> ConstantScoreQuery <$> parseJSON x
2285+ _ -> fail "Does not appear to be a ConstantScoreQuery"
2286+ queryDisMaxQuery = pure . QueryDisMaxQuery
2287+ queryFilteredQuery = pure . QueryFilteredQuery
2288+ queryFuzzyLikeThisQuery = pure . QueryFuzzyLikeThisQuery
2289+ queryFuzzyLikeFieldQuery = pure . QueryFuzzyLikeFieldQuery
2290+ queryFuzzyQuery = pure . QueryFuzzyQuery
2291+ queryHasChildQuery = pure . QueryHasChildQuery
2292+ queryHasParentQuery = pure . QueryHasParentQuery
2293+ queryIndicesQuery = pure . QueryIndicesQuery
2294+ matchAllQuery o = MatchAllQuery <$> o .:? "boost"
2295+ queryMoreLikeThisQuery = pure . QueryMoreLikeThisQuery
2296+ queryMoreLikeThisFieldQuery = pure . QueryMoreLikeThisFieldQuery
2297+ queryNestedQuery = pure . QueryNestedQuery
2298+ queryPrefixQuery = pure . QueryPrefixQuery
2299+ queryRangeQuery = pure . QueryRangeQuery
2300+ queryRegexpQuery = pure . QueryRegexpQuery
2301+ querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
2304+omitNulls :: [(Text, Value)] -> Value
2305+omitNulls = object . filter notNull where
2306+ notNull (_, Null) = False
2307+ notNull (_, Array a) = (not . V.null) a
2311+instance ToJSON SimpleQueryStringQuery where
2312+ toJSON SimpleQueryStringQuery {..} =
2313+ omitNulls (base ++ maybeAdd)
2314+ where base = [ "query" .= simpleQueryStringQuery ]
2315+ maybeAdd = [ "fields" .= simpleQueryStringField
2316+ , "default_operator" .= simpleQueryStringOperator
2317+ , "analyzer" .= simpleQueryStringAnalyzer
2318+ , "flags" .= simpleQueryStringFlags
2319+ , "lowercase_expanded_terms" .= simpleQueryStringLowercaseExpanded
2320+ , "locale" .= simpleQueryStringLocale ]
2322+instance FromJSON SimpleQueryStringQuery where
2323+ parseJSON = withObject "SimpleQueryStringQuery" parse
2324+ where parse o = SimpleQueryStringQuery <$> o .: "query"
2326+ <*> o .:? "default_operator"
2327+ <*> o .:? "analyzer"
2328+ <*> (parseFlags <$> o .:? "flags")
2329+ <*> o .:? "lowercase_expanded_terms"
2331+ parseFlags (Just (x:xs)) = Just (x :| xs)
2332+ parseFlags _ = Nothing
2334+instance ToJSON FieldOrFields where
2335+ toJSON (FofField fieldName) =
2337+ toJSON (FofFields fieldNames) =
2340+instance FromJSON FieldOrFields where
2341+ parseJSON v = FofField <$> parseJSON v
2342+ <|> FofFields <$> (parseNEJSON =<< parseJSON v)
2344+instance ToJSON SimpleQueryFlag where
2345+ toJSON SimpleQueryAll = "ALL"
2346+ toJSON SimpleQueryNone = "NONE"
2347+ toJSON SimpleQueryAnd = "AND"
2348+ toJSON SimpleQueryOr = "OR"
2349+ toJSON SimpleQueryPrefix = "PREFIX"
2350+ toJSON SimpleQueryPhrase = "PHRASE"
2351+ toJSON SimpleQueryPrecedence = "PRECEDENCE"
2352+ toJSON SimpleQueryEscape = "ESCAPE"
2353+ toJSON SimpleQueryWhitespace = "WHITESPACE"
2354+ toJSON SimpleQueryFuzzy = "FUZZY"
2355+ toJSON SimpleQueryNear = "NEAR"
2356+ toJSON SimpleQuerySlop = "SLOP"
2358+instance FromJSON SimpleQueryFlag where
2359+ parseJSON = withText "SimpleQueryFlag" parse
2360+ where parse "ALL" = pure SimpleQueryAll
2361+ parse "NONE" = pure SimpleQueryNone
2362+ parse "AND" = pure SimpleQueryAnd
2363+ parse "OR" = pure SimpleQueryOr
2364+ parse "PREFIX" = pure SimpleQueryPrefix
2365+ parse "PHRASE" = pure SimpleQueryPhrase
2366+ parse "PRECEDENCE" = pure SimpleQueryPrecedence
2367+ parse "ESCAPE" = pure SimpleQueryEscape
2368+ parse "WHITESPACE" = pure SimpleQueryWhitespace
2369+ parse "FUZZY" = pure SimpleQueryFuzzy
2370+ parse "NEAR" = pure SimpleQueryNear
2371+ parse "SLOP" = pure SimpleQuerySlop
2372+ parse f = fail ("Unexpected SimpleQueryFlag: " <> show f)
2374+instance ToJSON RegexpQuery where
2375+ toJSON (RegexpQuery (FieldName rqQueryField)
2376+ (Regexp regexpQueryQuery) rqQueryFlags
2378+ object [ rqQueryField .= omitNulls base ]
2379+ where base = [ "value" .= regexpQueryQuery
2380+ , "flags" .= rqQueryFlags
2381+ , "boost" .= rqQueryBoost ]
2383+instance FromJSON RegexpQuery where
2384+ parseJSON = withObject "RegexpQuery" parse
2385+ where parse = fieldTagged $ \fn o ->
2391+instance ToJSON QueryStringQuery where
2392+ toJSON (QueryStringQuery qsQueryString
2393+ qsDefaultField qsOperator
2394+ qsAnalyzer qsAllowWildcard
2395+ qsLowercaseExpanded qsEnablePositionIncrements
2396+ qsFuzzyMaxExpansions qsFuzziness
2397+ qsFuzzyPrefixLength qsPhraseSlop
2398+ qsBoost qsAnalyzeWildcard
2399+ qsGeneratePhraseQueries qsMinimumShouldMatch
2400+ qsLenient qsLocale) =
2403+ base = [ "query" .= qsQueryString
2404+ , "default_field" .= qsDefaultField
2405+ , "default_operator" .= qsOperator
2406+ , "analyzer" .= qsAnalyzer
2407+ , "allow_leading_wildcard" .= qsAllowWildcard
2408+ , "lowercase_expanded_terms" .= qsLowercaseExpanded
2409+ , "enable_position_increments" .= qsEnablePositionIncrements
2410+ , "fuzzy_max_expansions" .= qsFuzzyMaxExpansions
2411+ , "fuzziness" .= qsFuzziness
2412+ , "fuzzy_prefix_length" .= qsFuzzyPrefixLength
2413+ , "phrase_slop" .= qsPhraseSlop
2414+ , "boost" .= qsBoost
2415+ , "analyze_wildcard" .= qsAnalyzeWildcard
2416+ , "auto_generate_phrase_queries" .= qsGeneratePhraseQueries
2417+ , "minimum_should_match" .= qsMinimumShouldMatch
2418+ , "lenient" .= qsLenient
2419+ , "locale" .= qsLocale ]
2421+instance FromJSON QueryStringQuery where
2422+ parseJSON = withObject "QueryStringQuery" parse
2423+ where parse o = QueryStringQuery
2425+ <*> o .:? "default_field"
2426+ <*> o .:? "default_operator"
2427+ <*> o .:? "analyzer"
2428+ <*> o .:? "allow_leading_wildcard"
2429+ <*> o .:? "lowercase_expanded_terms"
2430+ <*> o .:? "enable_position_increments"
2431+ <*> o .:? "fuzzy_max_expansions"
2432+ <*> o .:? "fuzziness"
2433+ <*> o .:? "fuzzy_prefix_length"
2434+ <*> o .:? "phrase_slop"
2436+ <*> o .:? "analyze_wildcard"
2437+ <*> o .:? "auto_generate_phrase_queries"
2438+ <*> o .:? "minimum_should_match"
2439+ <*> o .:? "lenient"
2442+instance ToJSON RangeQuery where
2443+ toJSON (RangeQuery (FieldName fieldName) range boost) =
2444+ object [ fieldName .= object conjoined ]
2445+ where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
2447+instance FromJSON RangeQuery where
2448+ parseJSON = withObject "RangeQuery" parse
2449+ where parse = fieldTagged $ \fn o ->
2451+ <$> parseJSON (Object o)
2454+instance FromJSON RangeValue where
2455+ parseJSON = withObject "RangeValue" parse
2456+ where parse o = parseDate o
2458+ parseDate o = do lt <- o .:? "lt"
2462+ case (lt, lte, gt, gte) of
2463+ (Just a, _, Just b, _) -> return (RangeDateGtLt (GreaterThanD b) (LessThanD a))
2464+ (Just a, _, _, Just b)-> return (RangeDateGteLt (GreaterThanEqD b) (LessThanD a))
2465+ (_, Just a, Just b, _)-> return (RangeDateGtLte (GreaterThanD b) (LessThanEqD a))
2466+ (_, Just a, _, Just b)-> return (RangeDateGteLte (GreaterThanEqD b) (LessThanEqD a))
2467+ (_, _, Just a, _)-> return (RangeDateGt (GreaterThanD a))
2468+ (Just a, _, _, _)-> return (RangeDateLt (LessThanD a))
2469+ (_, _, _, Just a)-> return (RangeDateGte (GreaterThanEqD a))
2470+ (_, Just a, _, _)-> return (RangeDateLte (LessThanEqD a))
2471+ (Nothing, Nothing, Nothing, Nothing) -> mzero
2472+ parseDouble o = do lt <- o .:? "lt"
2476+ case (lt, lte, gt, gte) of
2477+ (Just a, _, Just b, _) -> return (RangeDoubleGtLt (GreaterThan b) (LessThan a))
2478+ (Just a, _, _, Just b)-> return (RangeDoubleGteLt (GreaterThanEq b) (LessThan a))
2479+ (_, Just a, Just b, _)-> return (RangeDoubleGtLte (GreaterThan b) (LessThanEq a))
2480+ (_, Just a, _, Just b)-> return (RangeDoubleGteLte (GreaterThanEq b) (LessThanEq a))
2481+ (_, _, Just a, _)-> return (RangeDoubleGt (GreaterThan a))
2482+ (Just a, _, _, _)-> return (RangeDoubleLt (LessThan a))
2483+ (_, _, _, Just a)-> return (RangeDoubleGte (GreaterThanEq a))
2484+ (_, Just a, _, _)-> return (RangeDoubleLte (LessThanEq a))
2485+ (Nothing, Nothing, Nothing, Nothing) -> mzero
2487+instance ToJSON PrefixQuery where
2488+ toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
2489+ object [ fieldName .= omitNulls base ]
2490+ where base = [ "value" .= queryValue
2491+ , "boost" .= boost ]
2493+instance FromJSON PrefixQuery where
2494+ parseJSON = withObject "PrefixQuery" parse
2495+ where parse = fieldTagged $ \fn o ->
2500+instance ToJSON NestedQuery where
2501+ toJSON (NestedQuery nqPath nqScoreType nqQuery) =
2502+ object [ "path" .= nqPath
2503+ , "score_mode" .= nqScoreType
2504+ , "query" .= nqQuery ]
2506+instance FromJSON NestedQuery where
2507+ parseJSON = withObject "NestedQuery" parse
2508+ where parse o = NestedQuery
2510+ <*> o .: "score_mode"
2513+instance ToJSON MoreLikeThisFieldQuery where
2514+ toJSON (MoreLikeThisFieldQuery text (FieldName fieldName)
2515+ percent mtf mqt stopwords mindf maxdf
2516+ minwl maxwl boostTerms boost analyzer) =
2517+ object [ fieldName .= omitNulls base ]
2518+ where base = [ "like_text" .= text
2519+ , "percent_terms_to_match" .= percent
2520+ , "min_term_freq" .= mtf
2521+ , "max_query_terms" .= mqt
2522+ , "stop_words" .= stopwords
2523+ , "min_doc_freq" .= mindf
2524+ , "max_doc_freq" .= maxdf
2525+ , "min_word_length" .= minwl
2526+ , "max_word_length" .= maxwl
2527+ , "boost_terms" .= boostTerms
2529+ , "analyzer" .= analyzer ]
2531+instance FromJSON MoreLikeThisFieldQuery where
2532+ parseJSON = withObject "MoreLikeThisFieldQuery" parse
2533+ where parse = fieldTagged $ \fn o ->
2534+ MoreLikeThisFieldQuery
2535+ <$> o .: "like_text"
2537+ <*> o .:? "percent_terms_to_match"
2538+ <*> o .:? "min_term_freq"
2539+ <*> o .:? "max_query_terms"
2540+ -- <*> (optionalNE =<< o .:? "stop_words")
2541+ <*> o .:? "stop_words"
2542+ <*> o .:? "min_doc_freq"
2543+ <*> o .:? "max_doc_freq"
2544+ <*> o .:? "min_word_length"
2545+ <*> o .:? "max_word_length"
2546+ <*> o .:? "boost_terms"
2548+ <*> o .:? "analyzer"
2549+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2551+instance ToJSON MoreLikeThisQuery where
2552+ toJSON (MoreLikeThisQuery text fields percent
2553+ mtf mqt stopwords mindf maxdf
2554+ minwl maxwl boostTerms boost analyzer) =
2556+ where base = [ "like_text" .= text
2557+ , "fields" .= fields
2558+ , "percent_terms_to_match" .= percent
2559+ , "min_term_freq" .= mtf
2560+ , "max_query_terms" .= mqt
2561+ , "stop_words" .= stopwords
2562+ , "min_doc_freq" .= mindf
2563+ , "max_doc_freq" .= maxdf
2564+ , "min_word_length" .= minwl
2565+ , "max_word_length" .= maxwl
2566+ , "boost_terms" .= boostTerms
2568+ , "analyzer" .= analyzer ]
2570+instance FromJSON MoreLikeThisQuery where
2571+ parseJSON = withObject "MoreLikeThisQuery" parse
2572+ where parse o = MoreLikeThisQuery
2573+ <$> o .: "like_text"
2574+ -- <*> (optionalNE =<< o .:? "fields")
2576+ <*> o .:? "percent_terms_to_match"
2577+ <*> o .:? "min_term_freq"
2578+ <*> o .:? "max_query_terms"
2579+ -- <*> (optionalNE =<< o .:? "stop_words")
2580+ <*> o .:? "stop_words"
2581+ <*> o .:? "min_doc_freq"
2582+ <*> o .:? "max_doc_freq"
2583+ <*> o .:? "min_word_length"
2584+ <*> o .:? "max_word_length"
2585+ <*> o .:? "boost_terms"
2587+ <*> o .:? "analyzer"
2588+ -- optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2590+instance ToJSON IndicesQuery where
2591+ toJSON (IndicesQuery indices query noMatch) =
2592+ omitNulls [ "indices" .= indices
2593+ , "no_match_query" .= noMatch
2594+ , "query" .= query ]
2596+instance FromJSON IndicesQuery where
2597+ parseJSON = withObject "IndicesQuery" parse
2598+ where parse o = IndicesQuery
2599+ <$> o .:? "indices" .!= []
2601+ <*> o .:? "no_match_query"
2603+instance ToJSON HasParentQuery where
2604+ toJSON (HasParentQuery queryType query scoreType) =
2605+ omitNulls [ "parent_type" .= queryType
2606+ , "score_type" .= scoreType
2607+ , "query" .= query ]
2609+instance FromJSON HasParentQuery where
2610+ parseJSON = withObject "HasParentQuery" parse
2611+ where parse o = HasParentQuery
2612+ <$> o .: "parent_type"
2614+ <*> o .:? "score_type"
2616+instance ToJSON HasChildQuery where
2617+ toJSON (HasChildQuery queryType query scoreType) =
2618+ omitNulls [ "query" .= query
2619+ , "score_type" .= scoreType
2620+ , "type" .= queryType ]
2622+instance FromJSON HasChildQuery where
2623+ parseJSON = withObject "HasChildQuery" parse
2624+ where parse o = HasChildQuery
2627+ <*> o .:? "score_type"
2629+instance ToJSON FuzzyQuery where
2630+ toJSON (FuzzyQuery (FieldName fieldName) queryText
2631+ prefixLength maxEx fuzziness boost) =
2632+ object [ fieldName .= omitNulls base ]
2633+ where base = [ "value" .= queryText
2634+ , "fuzziness" .= fuzziness
2635+ , "prefix_length" .= prefixLength
2637+ , "max_expansions" .= maxEx ]
2639+instance FromJSON FuzzyQuery where
2640+ parseJSON = withObject "FuzzyQuery" parse
2641+ where parse = fieldTagged $ \fn o ->
2644+ <*> o .: "prefix_length"
2645+ <*> o .: "max_expansions"
2646+ <*> o .: "fuzziness"
2649+instance ToJSON FuzzyLikeFieldQuery where
2650+ toJSON (FuzzyLikeFieldQuery (FieldName fieldName)
2651+ fieldText maxTerms ignoreFreq fuzziness prefixLength
2653+ object [ fieldName .=
2654+ omitNulls [ "like_text" .= fieldText
2655+ , "max_query_terms" .= maxTerms
2656+ , "ignore_tf" .= ignoreFreq
2657+ , "fuzziness" .= fuzziness
2658+ , "prefix_length" .= prefixLength
2659+ , "analyzer" .= analyzer
2660+ , "boost" .= boost ]]
2662+instance FromJSON FuzzyLikeFieldQuery where
2663+ parseJSON = withObject "FuzzyLikeFieldQuery" parse
2664+ where parse = fieldTagged $ \fn o ->
2665+ FuzzyLikeFieldQuery fn
2666+ <$> o .: "like_text"
2667+ <*> o .: "max_query_terms"
2668+ <*> o .: "ignore_tf"
2669+ <*> o .: "fuzziness"
2670+ <*> o .: "prefix_length"
2672+ <*> o .:? "analyzer"
2674+instance ToJSON FuzzyLikeThisQuery where
2675+ toJSON (FuzzyLikeThisQuery fields text maxTerms
2676+ ignoreFreq fuzziness prefixLength boost analyzer) =
2678+ where base = [ "fields" .= fields
2679+ , "like_text" .= text
2680+ , "max_query_terms" .= maxTerms
2681+ , "ignore_tf" .= ignoreFreq
2682+ , "fuzziness" .= fuzziness
2683+ , "prefix_length" .= prefixLength
2684+ , "analyzer" .= analyzer
2685+ , "boost" .= boost ]
2687+instance FromJSON FuzzyLikeThisQuery where
2688+ parseJSON = withObject "FuzzyLikeThisQuery" parse
2689+ where parse o = FuzzyLikeThisQuery
2690+ <$> o .:? "fields" .!= []
2691+ <*> o .: "like_text"
2692+ <*> o .: "max_query_terms"
2693+ <*> o .: "ignore_tf"
2694+ <*> o .: "fuzziness"
2695+ <*> o .: "prefix_length"
2697+ <*> o .:? "analyzer"
2699+instance ToJSON FilteredQuery where
2700+ toJSON (FilteredQuery query fFilter) =
2701+ object [ "query" .= query
2702+ , "filter" .= fFilter ]
2704+instance FromJSON FilteredQuery where
2705+ parseJSON = withObject "FilteredQuery" parse
2706+ where parse o = FilteredQuery
2710+instance ToJSON DisMaxQuery where
2711+ toJSON (DisMaxQuery queries tiebreaker boost) =
2713+ where base = [ "queries" .= queries
2715+ , "tie_breaker" .= tiebreaker ]
2717+instance FromJSON DisMaxQuery where
2718+ parseJSON = withObject "DisMaxQuery" parse
2719+ where parse o = DisMaxQuery
2720+ <$> o .:? "queries" .!= []
2721+ <*> o .: "tie_breaker"
2724+instance ToJSON CommonTermsQuery where
2725+ toJSON (CommonTermsQuery (FieldName fieldName)
2726+ (QueryString query) cf lfo hfo msm
2727+ boost analyzer disableCoord) =
2728+ object [fieldName .= omitNulls base ]
2729+ where base = [ "query" .= query
2730+ , "cutoff_frequency" .= cf
2731+ , "low_freq_operator" .= lfo
2732+ , "minimum_should_match" .= msm
2734+ , "analyzer" .= analyzer
2735+ , "disable_coord" .= disableCoord
2736+ , "high_freq_operator" .= hfo ]
2738+instance FromJSON CommonTermsQuery where
2739+ parseJSON = withObject "CommonTermsQuery" parse
2740+ where parse = fieldTagged $ \fn o ->
2741+ CommonTermsQuery fn
2743+ <*> o .: "cutoff_frequency"
2744+ <*> o .: "low_freq_operator"
2745+ <*> o .: "high_freq_operator"
2746+ <*> o .:? "minimum_should_match"
2748+ <*> o .:? "analyzer"
2749+ <*> o .:? "disable_coord"
2751+instance ToJSON CommonMinimumMatch where
2752+ toJSON (CommonMinimumMatch mm) = toJSON mm
2753+ toJSON (CommonMinimumMatchHighLow (MinimumMatchHighLow lowF highF)) =
2754+ object [ "low_freq" .= lowF
2755+ , "high_freq" .= highF ]
2757+instance FromJSON CommonMinimumMatch where
2758+ parseJSON v = parseMinimum v
2759+ <|> parseMinimumHighLow v
2760+ where parseMinimum = fmap CommonMinimumMatch . parseJSON
2761+ parseMinimumHighLow = fmap CommonMinimumMatchHighLow . withObject "CommonMinimumMatchHighLow" (\o ->
2762+ MinimumMatchHighLow
2763+ <$> o .: "low_freq"
2764+ <*> o .: "high_freq")
2767+instance ToJSON BoostingQuery where
2768+ toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
2769+ object [ "positive" .= bqPositiveQuery
2770+ , "negative" .= bqNegativeQuery
2771+ , "negative_boost" .= bqNegativeBoost ]
2773+instance FromJSON BoostingQuery where
2774+ parseJSON = withObject "BoostingQuery" parse
2775+ where parse o = BoostingQuery
2776+ <$> o .: "positive"
2777+ <*> o .: "negative"
2778+ <*> o .: "negative_boost"
2780+instance ToJSON BoolQuery where
2781+ toJSON (BoolQuery mustM notM shouldM bqMin boost disableCoord) =
2783+ where base = [ "must" .= mustM
2784+ , "must_not" .= notM
2785+ , "should" .= shouldM
2786+ , "minimum_should_match" .= bqMin
2788+ , "disable_coord" .= disableCoord ]
2790+instance FromJSON BoolQuery where
2791+ parseJSON = withObject "BoolQuery" parse
2792+ where parse o = BoolQuery
2793+ <$> o .:? "must" .!= []
2794+ <*> o .:? "must_not" .!= []
2795+ <*> o .:? "should" .!= []
2796+ <*> o .:? "minimum_should_match"
2798+ <*> o .:? "disable_coord"
2800+instance ToJSON MatchQuery where
2801+ toJSON (MatchQuery (FieldName fieldName)
2802+ (QueryString mqQueryString) booleanOperator
2803+ zeroTermsQuery cutoffFrequency matchQueryType
2804+ analyzer maxExpansions lenient boost) =
2805+ object [ fieldName .= omitNulls base ]
2806+ where base = [ "query" .= mqQueryString
2807+ , "operator" .= booleanOperator
2808+ , "zero_terms_query" .= zeroTermsQuery
2809+ , "cutoff_frequency" .= cutoffFrequency
2810+ , "type" .= matchQueryType
2811+ , "analyzer" .= analyzer
2812+ , "max_expansions" .= maxExpansions
2813+ , "lenient" .= lenient
2814+ , "boost" .= boost ]
2816+instance FromJSON MatchQuery where
2817+ parseJSON = withObject "MatchQuery" parse
2818+ where parse = fieldTagged $ \fn o ->
2821+ <*> o .: "operator"
2822+ <*> o .: "zero_terms_query"
2823+ <*> o .:? "cutoff_frequency"
2825+ <*> o .:? "analyzer"
2826+ <*> o .:? "max_expansions"
2827+ <*> o .:? "lenient"
2830+instance ToJSON MultiMatchQuery where
2831+ toJSON (MultiMatchQuery fields (QueryString query) boolOp
2832+ ztQ tb mmqt cf analyzer maxEx lenient) =
2833+ object ["multi_match" .= omitNulls base]
2834+ where base = [ "fields" .= fmap toJSON fields
2836+ , "operator" .= boolOp
2837+ , "zero_terms_query" .= ztQ
2838+ , "tiebreaker" .= tb
2840+ , "cutoff_frequency" .= cf
2841+ , "analyzer" .= analyzer
2842+ , "max_expansions" .= maxEx
2843+ , "lenient" .= lenient ]
2845+instance FromJSON MultiMatchQuery where
2846+ parseJSON = withObject "MultiMatchQuery" parse
2847+ where parse raw = do o <- raw .: "multi_match"
2849+ <$> o .:? "fields" .!= []
2851+ <*> o .: "operator"
2852+ <*> o .: "zero_terms_query"
2853+ <*> o .:? "tiebreaker"
2855+ <*> o .:? "cutoff_frequency"
2856+ <*> o .:? "analyzer"
2857+ <*> o .:? "max_expansions"
2858+ <*> o .:? "lenient"
2860+instance ToJSON MultiMatchQueryType where
2861+ toJSON MultiMatchBestFields = "best_fields"
2862+ toJSON MultiMatchMostFields = "most_fields"
2863+ toJSON MultiMatchCrossFields = "cross_fields"
2864+ toJSON MultiMatchPhrase = "phrase"
2865+ toJSON MultiMatchPhrasePrefix = "phrase_prefix"
2867+instance FromJSON MultiMatchQueryType where
2868+ parseJSON = withText "MultiMatchPhrasePrefix" parse
2869+ where parse "best_fields" = pure MultiMatchBestFields
2870+ parse "most_fields" = pure MultiMatchMostFields
2871+ parse "cross_fields" = pure MultiMatchCrossFields
2872+ parse "phrase" = pure MultiMatchPhrase
2873+ parse "phrase_prefix" = pure MultiMatchPhrasePrefix
2874+ parse t = fail ("Unexpected MultiMatchPhrasePrefix: " <> show t)
2876+instance ToJSON BooleanOperator where
2877+ toJSON And = String "and"
2878+ toJSON Or = String "or"
2880+instance FromJSON BooleanOperator where
2881+ parseJSON = withText "BooleanOperator" parse
2882+ where parse "and" = pure And
2883+ parse "or" = pure Or
2884+ parse o = fail ("Unexpected BooleanOperator: " <> show o)
2886+instance ToJSON ZeroTermsQuery where
2887+ toJSON ZeroTermsNone = String "none"
2888+ toJSON ZeroTermsAll = String "all"
2890+instance FromJSON ZeroTermsQuery where
2891+ parseJSON = withText "ZeroTermsQuery" parse
2892+ where parse "none" = pure ZeroTermsNone
2893+ parse "all" = pure ZeroTermsAll
2894+ parse q = fail ("Unexpected ZeroTermsQuery: " <> show q)
2896+instance ToJSON MatchQueryType where
2897+ toJSON MatchPhrase = "phrase"
2898+ toJSON MatchPhrasePrefix = "phrase_prefix"
2900+instance FromJSON MatchQueryType where
2901+ parseJSON = withText "MatchQueryType" parse
2902+ where parse "phrase" = pure MatchPhrase
2903+ parse "phrase_prefix" = pure MatchPhrasePrefix
2904+ parse t = fail ("Unexpected MatchQueryType: " <> show t)
2906+instance FromJSON Status where
2907+ parseJSON (Object v) = Status <$>
2913+ parseJSON _ = empty
2916+instance ToJSON IndexSettings where
2917+ toJSON (IndexSettings s r) = object ["settings" .=
2919+ object ["number_of_shards" .= s, "number_of_replicas" .= r]
2923+instance FromJSON IndexSettings where
2924+ parseJSON = withObject "IndexSettings" parse
2925+ where parse o = do s <- o .: "settings"
2927+ IndexSettings <$> i .: "number_of_shards"
2928+ <*> i .: "number_of_replicas"
2930+instance ToJSON UpdatableIndexSetting where
2931+ toJSON (NumberOfReplicas x) = oPath ("index" :| ["number_of_replicas"]) x
2932+ toJSON (AutoExpandReplicas x) = oPath ("index" :| ["auto_expand_replicas"]) x
2933+ toJSON (RefreshInterval x) = oPath ("index" :| ["refresh_interval"]) (NominalDiffTimeJSON x)
2934+ toJSON (IndexConcurrency x) = oPath ("index" :| ["concurrency"]) x
2935+ toJSON (FailOnMergeFailure x) = oPath ("index" :| ["fail_on_merge_failure"]) x
2936+ toJSON (TranslogFlushThresholdOps x) = oPath ("index" :| ["translog", "flush_threshold_ops"]) x
2937+ toJSON (TranslogFlushThresholdSize x) = oPath ("index" :| ["translog", "flush_threshold_size"]) x
2938+ toJSON (TranslogFlushThresholdPeriod x) = oPath ("index" :| ["translog", "flush_threshold_period"]) (NominalDiffTimeJSON x)
2939+ toJSON (TranslogDisableFlush x) = oPath ("index" :| ["translog", "disable_flush"]) x
2940+ toJSON (CacheFilterMaxSize x) = oPath ("index" :| ["cache", "filter", "max_size"]) x
2941+ toJSON (CacheFilterExpire x) = oPath ("index" :| ["cache", "filter", "expire"]) (NominalDiffTimeJSON <$> x)
2942+ toJSON (GatewaySnapshotInterval x) = oPath ("index" :| ["gateway", "snapshot_interval"]) (NominalDiffTimeJSON x)
2943+ toJSON (RoutingAllocationInclude fs) = oPath ("index" :| ["routing", "allocation", "include"]) (attrFilterJSON fs)
2944+ toJSON (RoutingAllocationExclude fs) = oPath ("index" :| ["routing", "allocation", "exclude"]) (attrFilterJSON fs)
2945+ toJSON (RoutingAllocationRequire fs) = oPath ("index" :| ["routing", "allocation", "require"]) (attrFilterJSON fs)
2946+ toJSON (RoutingAllocationEnable x) = oPath ("index" :| ["routing", "allocation", "enable"]) x
2947+ toJSON (RoutingAllocationShardsPerNode x) = oPath ("index" :| ["routing", "allocation", "total_shards_per_node"]) x
2948+ toJSON (RecoveryInitialShards x) = oPath ("index" :| ["recovery", "initial_shards"]) x
2949+ toJSON (GCDeletes x) = oPath ("index" :| ["gc_deletes"]) (NominalDiffTimeJSON x)
2950+ toJSON (TTLDisablePurge x) = oPath ("index" :| ["ttl", "disable_purge"]) x
2951+ toJSON (TranslogFSType x) = oPath ("index" :| ["translog", "fs", "type"]) x
2952+ toJSON (IndexCompoundFormat x) = oPath ("index" :| ["compound_format"]) x
2953+ toJSON (IndexCompoundOnFlush x) = oPath ("index" :| ["compound_on_flush"]) x
2954+ toJSON (WarmerEnabled x) = oPath ("index" :| ["warmer", "enabled"]) x
2955+ toJSON (BlocksReadOnly x) = oPath ("blocks" :| ["read_only"]) x
2956+ toJSON (BlocksRead x) = oPath ("blocks" :| ["read"]) x
2957+ toJSON (BlocksWrite x) = oPath ("blocks" :| ["write"]) x
2958+ toJSON (BlocksMetaData x) = oPath ("blocks" :| ["metadata"]) x
2960+instance FromJSON UpdatableIndexSetting where
2961+ parseJSON = withObject "UpdatableIndexSetting" parse
2962+ where parse o = numberOfReplicas `taggedAt` ["index", "number_of_replicas"]
2963+ <|> autoExpandReplicas `taggedAt` ["index", "auto_expand_replicas"]
2964+ <|> refreshInterval `taggedAt` ["index", "refresh_interval"]
2965+ <|> indexConcurrency `taggedAt` ["index", "concurrency"]
2966+ <|> failOnMergeFailure `taggedAt` ["index", "fail_on_merge_failure"]
2967+ <|> translogFlushThresholdOps `taggedAt` ["index", "translog", "flush_threshold_ops"]
2968+ <|> translogFlushThresholdSize `taggedAt` ["index", "translog", "flush_threshold_size"]
2969+ <|> translogFlushThresholdPeriod `taggedAt` ["index", "translog", "flush_threshold_period"]
2970+ <|> translogDisableFlush `taggedAt` ["index", "translog", "disable_flush"]
2971+ <|> cacheFilterMaxSize `taggedAt` ["index", "cache", "filter", "max_size"]
2972+ <|> cacheFilterExpire `taggedAt` ["index", "cache", "filter", "expire"]
2973+ <|> gatewaySnapshotInterval `taggedAt` ["index", "gateway", "snapshot_interval"]
2974+ <|> routingAllocationInclude `taggedAt` ["index", "routing", "allocation", "include"]
2975+ <|> routingAllocationExclude `taggedAt` ["index", "routing", "allocation", "exclude"]
2976+ <|> routingAllocationRequire `taggedAt` ["index", "routing", "allocation", "require"]
2977+ <|> routingAllocationEnable `taggedAt` ["index", "routing", "allocation", "enable"]
2978+ <|> routingAllocationShardsPerNode `taggedAt` ["index", "routing", "allocation", "total_shards_per_node"]
2979+ <|> recoveryInitialShards `taggedAt` ["index", "recovery", "initial_shards"]
2980+ <|> gcDeletes `taggedAt` ["index", "gc_deletes"]
2981+ <|> ttlDisablePurge `taggedAt` ["index", "ttl", "disable_purge"]
2982+ <|> translogFSType `taggedAt` ["index", "translog", "fs", "type"]
2983+ <|> compoundFormat `taggedAt` ["index", "compound_format"]
2984+ <|> compoundOnFlush `taggedAt` ["index", "compound_on_flush"]
2985+ <|> warmerEnabled `taggedAt` ["index", "warmer", "enabled"]
2986+ <|> blocksReadOnly `taggedAt` ["blocks", "read_only"]
2987+ <|> blocksRead `taggedAt` ["blocks", "read"]
2988+ <|> blocksWrite `taggedAt` ["blocks", "write"]
2989+ <|> blocksMetaData `taggedAt` ["blocks", "metadata"]
2990+ where taggedAt f ks = taggedAt' f (Object o) ks
2991+ taggedAt' f v [] = f =<< (parseJSON v <|> (parseJSON =<< unStringlyTypeJSON v))
2992+ taggedAt' f v (k:ks) = withObject "Object" (\o -> do v' <- o .: k
2993+ taggedAt' f v' ks) v
2994+ numberOfReplicas = pure . NumberOfReplicas
2995+ autoExpandReplicas = pure . AutoExpandReplicas
2996+ refreshInterval = pure . RefreshInterval . ndtJSON
2997+ indexConcurrency = pure . IndexConcurrency
2998+ failOnMergeFailure = pure . FailOnMergeFailure
2999+ translogFlushThresholdOps = pure . TranslogFlushThresholdOps
3000+ translogFlushThresholdSize = pure . TranslogFlushThresholdSize
3001+ translogFlushThresholdPeriod = pure . TranslogFlushThresholdPeriod . ndtJSON
3002+ translogDisableFlush = pure . TranslogDisableFlush
3003+ cacheFilterMaxSize = pure . CacheFilterMaxSize
3004+ cacheFilterExpire = pure . CacheFilterExpire . fmap ndtJSON
3005+ gatewaySnapshotInterval = pure . GatewaySnapshotInterval . ndtJSON
3006+ routingAllocationInclude = fmap RoutingAllocationInclude . parseAttrFilter
3007+ routingAllocationExclude = fmap RoutingAllocationExclude . parseAttrFilter
3008+ routingAllocationRequire = fmap RoutingAllocationRequire . parseAttrFilter
3009+ routingAllocationEnable = pure . RoutingAllocationEnable
3010+ routingAllocationShardsPerNode = pure . RoutingAllocationShardsPerNode
3011+ recoveryInitialShards = pure . RecoveryInitialShards
3012+ gcDeletes = pure . GCDeletes . ndtJSON
3013+ ttlDisablePurge = pure . TTLDisablePurge
3014+ translogFSType = pure . TranslogFSType
3015+ compoundFormat = pure . IndexCompoundFormat
3016+ compoundOnFlush = pure . IndexCompoundOnFlush
3017+ warmerEnabled = pure . WarmerEnabled
3018+ blocksReadOnly = pure . BlocksReadOnly
3019+ blocksRead = pure . BlocksRead
3020+ blocksWrite = pure . BlocksWrite
3021+ blocksMetaData = pure . BlocksMetaData
3023+instance FromJSON IndexSettingsSummary where
3024+ parseJSON = withObject "IndexSettingsSummary" parse
3025+ where parse o = case HM.toList o of
3026+ [(ixn, v@(Object o'))] -> IndexSettingsSummary (IndexName ixn)
3028+ <*> (fmap (filter (not . redundant)) . parseSettings =<< o' .: "settings")
3029+ _ -> fail "Expected single-key object with index name"
3030+ redundant (NumberOfReplicas _) = True
3031+ redundant _ = False
3033+-- | For some reason in the settings API, all leaf values get returned
3034+-- as strings. This function attepmts to recover from this for all
3035+-- non-recursive JSON types. If nothing can be done or the same value
3036+-- would be return, it returns 'mzero'
3037+unStringlyTypeJSON :: MonadPlus m => Value -> m Value
3038+unStringlyTypeJSON (String "true") = return (Bool True)
3039+unStringlyTypeJSON (String "false") = return (Bool False)
3040+unStringlyTypeJSON (String "null") = return Null
3041+unStringlyTypeJSON (String t) = case readMay (T.unpack t) of
3042+ Just n -> return (Number n)
3044+unStringlyTypeJSON _ = mzero
3047+parseSettings :: Object -> Parser [UpdatableIndexSetting]
3048+parseSettings o = do
3050+ -- slice the index object into singleton hashmaps and try to parse each
3051+ parses <- forM (HM.toList o') $ \(k, v) -> do
3052+ -- blocks are now nested into the "index" key, which is not how they're serialized
3053+ let atRoot = Object (HM.singleton k v)
3054+ let atIndex = Object (HM.singleton "index" atRoot)
3055+ optional (parseJSON atRoot <|> parseJSON atIndex)
3056+ return (catMaybes parses)
3058+oPath :: ToJSON a => NonEmpty Text -> a -> Value
3059+oPath (k :| []) v = object [k .= v]
3060+oPath (k:| (h:t)) v = object [k .= oPath (h :| t) v]
3062+attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
3063+attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
3064+ | NodeAttrFilter (NodeAttrName n) vs <- toList fs]
3066+parseAttrFilter :: Value -> Parser (NonEmpty NodeAttrFilter)
3067+parseAttrFilter = withObject "NonEmpty NodeAttrFilter" parse
3068+ where parse o = case HM.toList o of
3069+ [] -> fail "Expected non-empty list of NodeAttrFilters"
3070+ x:xs -> DT.mapM (uncurry parse') (x :| xs)
3071+ parse' n = withText "Text" $ \t ->
3072+ case T.splitOn "," t of
3073+ fv:fvs -> return (NodeAttrFilter (NodeAttrName n) (fv :| fvs))
3074+ [] -> fail "Expected non-empty list of filter values"
3076+instance ToJSON ReplicaBounds where
3077+ toJSON (ReplicasBounded a b) = String (showText a <> "-" <> showText b)
3078+ toJSON (ReplicasLowerBounded a) = String (showText a <> "-all")
3079+ toJSON ReplicasUnbounded = Bool False
3081+instance FromJSON ReplicaBounds where
3082+ parseJSON v = withText "ReplicaBounds" parseText v
3083+ <|> withBool "ReplicaBounds" parseBool v
3084+ where parseText t = case T.splitOn "-" t of
3085+ [a, "all"] -> ReplicasLowerBounded <$> parseReadText a
3086+ [a, b] -> ReplicasBounded <$> parseReadText a
3087+ <*> parseReadText b
3088+ _ -> fail ("Could not parse ReplicaBounds: " <> show t)
3089+ parseBool False = pure ReplicasUnbounded
3090+ parseBool _ = fail "ReplicasUnbounded cannot be represented with True"
3092+instance ToJSON AllocationPolicy where
3093+ toJSON AllocAll = String "all"
3094+ toJSON AllocPrimaries = String "primaries"
3095+ toJSON AllocNewPrimaries = String "new_primaries"
3096+ toJSON AllocNone = String "none"
3098+instance FromJSON AllocationPolicy where
3099+ parseJSON = withText "AllocationPolicy" parse
3100+ where parse "all" = pure AllocAll
3101+ parse "primaries" = pure AllocPrimaries
3102+ parse "new_primaries" = pure AllocNewPrimaries
3103+ parse "none" = pure AllocNone
3104+ parse t = fail ("Invlaid AllocationPolicy: " <> show t)
3106+instance ToJSON InitialShardCount where
3107+ toJSON QuorumShards = String "quorum"
3108+ toJSON QuorumMinus1Shards = String "quorum-1"
3109+ toJSON FullShards = String "full"
3110+ toJSON FullMinus1Shards = String "full-1"
3111+ toJSON (ExplicitShards x) = toJSON x
3113+instance FromJSON InitialShardCount where
3114+ parseJSON v = withText "InitialShardCount" parseText v
3115+ <|> ExplicitShards <$> parseJSON v
3116+ where parseText "quorum" = pure QuorumShards
3117+ parseText "quorum-1" = pure QuorumMinus1Shards
3118+ parseText "full" = pure FullShards
3119+ parseText "full-1" = pure FullMinus1Shards
3120+ parseText _ = mzero
3122+instance ToJSON FSType where
3123+ toJSON FSSimple = "simple"
3124+ toJSON FSBuffered = "buffered"
3126+instance FromJSON FSType where
3127+ parseJSON = withText "FSType" parse
3128+ where parse "simple" = pure FSSimple
3129+ parse "buffered" = pure FSBuffered
3130+ parse t = fail ("Invalid FSType: " <> show t)
3132+instance ToJSON CompoundFormat where
3133+ toJSON (CompoundFileFormat x) = Bool x
3134+ toJSON (MergeSegmentVsTotalIndex x) = toJSON x
3136+instance FromJSON CompoundFormat where
3137+ parseJSON v = CompoundFileFormat <$> parseJSON v
3138+ <|> MergeSegmentVsTotalIndex <$> parseJSON v
3140+instance ToJSON NominalDiffTimeJSON where
3141+ toJSON (NominalDiffTimeJSON t) = String (showText (round t :: Integer) <> "s")
3143+instance FromJSON NominalDiffTimeJSON where
3144+ parseJSON = withText "NominalDiffTime" parse
3145+ where parse t = case T.takeEnd 1 t of
3146+ "s" -> NominalDiffTimeJSON . fromInteger <$> parseReadText (T.dropEnd 1 t)
3147+ _ -> fail "Invalid or missing NominalDiffTime unit (expected s)"
3149+instance ToJSON IndexTemplate where
3150+ toJSON (IndexTemplate p s m) = merge
3151+ (object [ "template" .= p
3152+ , "mappings" .= foldl' merge (object []) m
3156+ merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2
3158+ merge _ _ = undefined
3160+instance (FromJSON a) => FromJSON (EsResult a) where
3161+ parseJSON jsonVal@(Object v) = do
3162+ found <- v .:? "found" .!= False
3164+ then parseJSON jsonVal
3165+ else return Nothing
3166+ EsResult <$> v .: "_index" <*>
3170+ parseJSON _ = empty
3172+instance (FromJSON a) => FromJSON (EsResultFound a) where
3173+ parseJSON (Object v) = EsResultFound <$>
3174+ v .: "_version" <*>
3176+ parseJSON _ = empty
3178+instance FromJSON EsError where
3179+ parseJSON (Object v) = EsError <$>
3182+ parseJSON _ = empty
3184+instance FromJSON IndexAliasesSummary where
3185+ parseJSON = withObject "IndexAliasesSummary" parse
3186+ where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (HM.toList o)
3187+ go ixn = withObject "index aliases" $ \ia -> do
3188+ aliases <- ia .:? "aliases" .!= mempty
3189+ forM (HM.toList aliases) $ \(aName, v) -> do
3190+ let indexAlias = IndexAlias (IndexName ixn) (IndexAliasName (IndexName aName))
3191+ IndexAliasSummary indexAlias <$> parseJSON v
3194+instance ToJSON IndexAliasAction where
3195+ toJSON (AddAlias ia opts) = object ["add" .= (iaObj <> optsObj)]
3196+ where Object iaObj = toJSON ia
3197+ Object optsObj = toJSON opts
3198+ toJSON (RemoveAlias ia) = object ["remove" .= iaObj]
3199+ where Object iaObj = toJSON ia
3201+instance ToJSON IndexAlias where
3202+ toJSON IndexAlias {..} = object ["index" .= srcIndex
3203+ , "alias" .= indexAlias
3206+instance ToJSON IndexAliasCreate where
3207+ toJSON IndexAliasCreate {..} = Object (filterObj <> routingObj)
3208+ where filterObj = maybe mempty (HM.singleton "filter" . toJSON) aliasCreateFilter
3209+ Object routingObj = maybe (Object mempty) toJSON aliasCreateRouting
3211+instance ToJSON AliasRouting where
3212+ toJSON (AllAliasRouting v) = object ["routing" .= v]
3213+ toJSON (GranularAliasRouting srch idx) = object (catMaybes prs)
3214+ where prs = [("search_routing" .=) <$> srch
3215+ ,("index_routing" .=) <$> idx]
3217+instance FromJSON AliasRouting where
3218+ parseJSON = withObject "AliasRouting" parse
3219+ where parse o = parseAll o <|> parseGranular o
3220+ parseAll o = AllAliasRouting <$> o .: "routing"
3221+ parseGranular o = do
3222+ sr <- o .:? "search_routing"
3223+ ir <- o .:? "index_routing"
3224+ if isNothing sr && isNothing ir
3225+ then fail "Both search_routing and index_routing can't be blank"
3226+ else return (GranularAliasRouting sr ir)
3228+instance FromJSON IndexAliasCreate where
3229+ parseJSON v = withObject "IndexAliasCreate" parse v
3230+ where parse o = IndexAliasCreate <$> optional (parseJSON v)
3233+instance ToJSON SearchAliasRouting where
3234+ toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
3236+instance FromJSON SearchAliasRouting where
3237+ parseJSON = withText "SearchAliasRouting" parse
3238+ where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
3240+instance ToJSON Search where
3241+ toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
3242+ omitNulls [ "query" .= query
3243+ , "filter" .= sFilter
3245+ , "aggregations" .= searchAggs
3246+ , "highlight" .= highlight
3249+ , "track_scores" .= sTrackSortScores
3250+ , "fields" .= sFields
3251+ , "_source" .= sSource]
3254+instance ToJSON Source where
3255+ toJSON NoSource = toJSON False
3256+ toJSON (SourcePatterns patterns) = toJSON patterns
3257+ toJSON (SourceIncludeExclude incl excl) = object [ "include" .= incl, "exclude" .= excl ]
3259+instance ToJSON PatternOrPatterns where
3260+ toJSON (PopPattern pattern) = toJSON pattern
3261+ toJSON (PopPatterns patterns) = toJSON patterns
3263+instance ToJSON Include where
3264+ toJSON (Include patterns) = toJSON patterns
3266+instance ToJSON Exclude where
3267+ toJSON (Exclude patterns) = toJSON patterns
3269+instance ToJSON Pattern where
3270+ toJSON (Pattern pattern) = toJSON pattern
3273+instance ToJSON FieldHighlight where
3274+ toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =
3275+ object [ fName .= fSettings ]
3276+ toJSON (FieldHighlight (FieldName fName) Nothing) =
3277+ object [ fName .= emptyObject ]
3279+instance ToJSON Highlights where
3280+ toJSON (Highlights global fields) =
3281+ omitNulls (("fields" .= fields)
3282+ : highlightSettingsPairs global)
3284+instance ToJSON HighlightSettings where
3285+ toJSON hs = omitNulls (highlightSettingsPairs (Just hs))
3287+highlightSettingsPairs :: Maybe HighlightSettings -> [Pair]
3288+highlightSettingsPairs Nothing = []
3289+highlightSettingsPairs (Just (Plain plh)) = plainHighPairs (Just plh)
3290+highlightSettingsPairs (Just (Postings ph)) = postHighPairs (Just ph)
3291+highlightSettingsPairs (Just (FastVector fvh)) = fastVectorHighPairs (Just fvh)
3294+plainHighPairs :: Maybe PlainHighlight -> [Pair]
3295+plainHighPairs Nothing = []
3296+plainHighPairs (Just (PlainHighlight plCom plNonPost)) =
3297+ [ "type" .= String "plain"]
3298+ ++ commonHighlightPairs plCom
3299+ ++ nonPostingsToPairs plNonPost
3301+postHighPairs :: Maybe PostingsHighlight -> [Pair]
3302+postHighPairs Nothing = []
3303+postHighPairs (Just (PostingsHighlight pCom)) =
3304+ ("type" .= String "postings")
3305+ : commonHighlightPairs pCom
3307+fastVectorHighPairs :: Maybe FastVectorHighlight -> [Pair]
3308+fastVectorHighPairs Nothing = []
3309+fastVectorHighPairs (Just
3310+ (FastVectorHighlight fvCom fvNonPostSettings fvBoundChars
3311+ fvBoundMaxScan fvFragOff fvMatchedFields
3313+ [ "type" .= String "fvh"
3314+ , "boundary_chars" .= fvBoundChars
3315+ , "boundary_max_scan" .= fvBoundMaxScan
3316+ , "fragment_offset" .= fvFragOff
3317+ , "matched_fields" .= fvMatchedFields
3318+ , "phraseLimit" .= fvPhraseLim]
3319+ ++ commonHighlightPairs fvCom
3320+ ++ nonPostingsToPairs fvNonPostSettings
3322+deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
3323+deleteSeveral ks hm = foldr HM.delete hm ks
3325+commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
3326+commonHighlightPairs Nothing = []
3327+commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
3328+ chNoMatchSize chHighlightQuery
3329+ chRequireFieldMatch)) =
3330+ [ "order" .= chScore
3331+ , "force_source" .= chForceSource
3332+ , "encoder" .= chEncoder
3333+ , "no_match_size" .= chNoMatchSize
3334+ , "highlight_query" .= chHighlightQuery
3335+ , "require_fieldMatch" .= chRequireFieldMatch]
3336+ ++ highlightTagToPairs chTag
3339+nonPostingsToPairs :: Maybe NonPostings -> [Pair]
3340+nonPostingsToPairs Nothing = []
3341+nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
3342+ [ "fragment_size" .= npFragSize
3343+ , "number_of_fragments" .= npNumOfFrags]
3345+parseNEJSON :: (FromJSON a) => [Value] -> Parser (NonEmpty a)
3346+parseNEJSON [] = fail "Expected non-empty list"
3347+parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
3350+instance ToJSON HighlightEncoder where
3351+ toJSON DefaultEncoder = String "default"
3352+ toJSON HTMLEncoder = String "html"
3354+highlightTagToPairs :: Maybe HighlightTag -> [Pair]
3355+highlightTagToPairs (Just (TagSchema _)) = [ "scheme" .= String "default"]
3356+highlightTagToPairs (Just (CustomTags (pre, post))) = [ "pre_tags" .= pre
3357+ , "post_tags" .= post]
3358+highlightTagToPairs Nothing = []
3360+instance ToJSON SortSpec where
3361+ toJSON (DefaultSortSpec
3362+ (DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped
3363+ dsSortMode dsMissingSort dsNestedFilter)) =
3364+ object [dsSortFieldName .= omitNulls base] where
3365+ base = [ "order" .= dsSortOrder
3366+ , "ignore_unmapped" .= dsIgnoreUnmapped
3367+ , "mode" .= dsSortMode
3368+ , "missing" .= dsMissingSort
3369+ , "nested_filter" .= dsNestedFilter ]
3371+ toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) =
3372+ object [ "unit" .= units
3373+ , field .= gdsLatLon
3374+ , "order" .= gdsSortOrder ]
3377+instance ToJSON SortOrder where
3378+ toJSON Ascending = String "asc"
3379+ toJSON Descending = String "desc"
3382+instance ToJSON SortMode where
3383+ toJSON SortMin = String "min"
3384+ toJSON SortMax = String "max"
3385+ toJSON SortSum = String "sum"
3386+ toJSON SortAvg = String "avg"
3389+instance ToJSON Missing where
3390+ toJSON LastMissing = String "_last"
3391+ toJSON FirstMissing = String "_first"
3392+ toJSON (CustomMissing txt) = String txt
3395+instance ToJSON ScoreType where
3396+ toJSON ScoreTypeMax = "max"
3397+ toJSON ScoreTypeAvg = "avg"
3398+ toJSON ScoreTypeSum = "sum"
3399+ toJSON ScoreTypeNone = "none"
3401+instance FromJSON ScoreType where
3402+ parseJSON = withText "ScoreType" parse
3403+ where parse "max" = pure ScoreTypeMax
3404+ parse "avg" = pure ScoreTypeAvg
3405+ parse "sum" = pure ScoreTypeSum
3406+ parse "none" = pure ScoreTypeNone
3407+ parse t = fail ("Unexpected ScoreType: " <> show t)
3409+instance ToJSON Distance where
3410+ toJSON (Distance dCoefficient dUnit) =
3411+ String boltedTogether where
3412+ coefText = showText dCoefficient
3413+ (String unitText) = toJSON dUnit
3414+ boltedTogether = mappend coefText unitText
3416+instance FromJSON Distance where
3417+ parseJSON = withText "Distance" parse
3418+ where parse t = Distance <$> parseCoeff nT
3419+ <*> parseJSON (String unitT)
3420+ where (nT, unitT) = T.span validForNumber t
3421+ -- may be a better way to do this
3422+ validForNumber '-' = True
3423+ validForNumber '.' = True
3424+ validForNumber 'e' = True
3425+ validForNumber c = isNumber c
3426+ parseCoeff "" = fail "Empty string cannot be parsed as number"
3427+ parseCoeff s = return (read (T.unpack s))
3429+instance ToJSON DistanceUnit where
3430+ toJSON Miles = String "mi"
3431+ toJSON Yards = String "yd"
3432+ toJSON Feet = String "ft"
3433+ toJSON Inches = String "in"
3434+ toJSON Kilometers = String "km"
3435+ toJSON Meters = String "m"
3436+ toJSON Centimeters = String "cm"
3437+ toJSON Millimeters = String "mm"
3438+ toJSON NauticalMiles = String "nmi"
3441+instance FromJSON DistanceUnit where
3442+ parseJSON = withText "DistanceUnit" parse
3443+ where parse "mi" = pure Miles
3444+ parse "yd" = pure Yards
3445+ parse "ft" = pure Feet
3446+ parse "in" = pure Inches
3447+ parse "km" = pure Kilometers
3448+ parse "m" = pure Meters
3449+ parse "cm" = pure Centimeters
3450+ parse "mm" = pure Millimeters
3451+ parse "nmi" = pure NauticalMiles
3452+ parse u = fail ("Unrecognized DistanceUnit: " <> show u)
3454+instance ToJSON DistanceType where
3455+ toJSON Arc = String "arc"
3456+ toJSON SloppyArc = String "sloppy_arc"
3457+ toJSON Plane = String "plane"
3459+instance FromJSON DistanceType where
3460+ parseJSON = withText "DistanceType" parse
3461+ where parse "arc" = pure Arc
3462+ parse "sloppy_arc" = pure SloppyArc
3463+ parse "plane" = pure Plane
3464+ parse t = fail ("Unrecognized DistanceType: " <> show t)
3467+instance ToJSON OptimizeBbox where
3468+ toJSON NoOptimizeBbox = String "none"
3469+ toJSON (OptimizeGeoFilterType gft) = toJSON gft
3471+instance FromJSON OptimizeBbox where
3472+ parseJSON v = withText "NoOptimizeBbox" parseNoOptimize v
3473+ <|> parseOptimize v
3474+ where parseNoOptimize "none" = pure NoOptimizeBbox
3475+ parseNoOptimize _ = mzero
3476+ parseOptimize = fmap OptimizeGeoFilterType . parseJSON
3478+instance ToJSON GeoBoundingBoxConstraint where
3479+ toJSON (GeoBoundingBoxConstraint
3480+ (FieldName gbbcGeoBBField) gbbcConstraintBox cache type') =
3481+ object [gbbcGeoBBField .= gbbcConstraintBox
3482+ , "_cache" .= cache
3485+instance FromJSON GeoBoundingBoxConstraint where
3486+ parseJSON = withObject "GeoBoundingBoxConstraint" parse
3487+ where parse o = case HM.toList (deleteSeveral ["type", "_cache"] o) of
3488+ [(fn, v)] -> GeoBoundingBoxConstraint (FieldName fn)
3490+ <*> o .:? "_cache" .!= defaultCache
3492+ _ -> fail "Could not find field name for GeoBoundingBoxConstraint"
3494+instance ToJSON GeoFilterType where
3495+ toJSON GeoFilterMemory = String "memory"
3496+ toJSON GeoFilterIndexed = String "indexed"
3498+instance FromJSON GeoFilterType where
3499+ parseJSON = withText "GeoFilterType" parse
3500+ where parse "memory" = pure GeoFilterMemory
3501+ parse "indexed" = pure GeoFilterIndexed
3502+ parse t = fail ("Unrecognized GeoFilterType: " <> show t)
3504+instance ToJSON GeoBoundingBox where
3505+ toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
3506+ object ["top_left" .= gbbTopLeft
3507+ , "bottom_right" .= gbbBottomRight]
3509+instance FromJSON GeoBoundingBox where
3510+ parseJSON = withObject "GeoBoundingBox" parse
3511+ where parse o = GeoBoundingBox
3512+ <$> o .: "top_left"
3513+ <*> o .: "bottom_right"
3515+instance ToJSON LatLon where
3516+ toJSON (LatLon lLat lLon) =
3517+ object ["lat" .= lLat
3520+instance FromJSON LatLon where
3521+ parseJSON = withObject "LatLon" parse
3522+ where parse o = LatLon <$> o .: "lat"
3525+-- index for smaller ranges, fielddata for longer ranges
3526+instance ToJSON RangeExecution where
3527+ toJSON RangeExecutionIndex = "index"
3528+ toJSON RangeExecutionFielddata = "fielddata"
3531+instance FromJSON RangeExecution where
3532+ parseJSON = withText "RangeExecution" parse
3533+ where parse "index" = pure RangeExecutionIndex
3534+ parse "fielddata" = pure RangeExecutionFielddata
3535+ parse t = error ("Unrecognized RangeExecution " <> show t)
3537+instance ToJSON RegexpFlags where
3538+ toJSON AllRegexpFlags = String "ALL"
3539+ toJSON NoRegexpFlags = String "NONE"
3540+ toJSON (SomeRegexpFlags (h :| fs)) = String $ T.intercalate "|" flagStrs
3541+ where flagStrs = map flagStr . nub $ h:fs
3542+ flagStr AnyString = "ANYSTRING"
3543+ flagStr Automaton = "AUTOMATON"
3544+ flagStr Complement = "COMPLEMENT"
3545+ flagStr Empty = "EMPTY"
3546+ flagStr Intersection = "INTERSECTION"
3547+ flagStr Interval = "INTERVAL"
3549+instance FromJSON RegexpFlags where
3550+ parseJSON = withText "RegexpFlags" parse
3551+ where parse "ALL" = pure AllRegexpFlags
3552+ parse "NONE" = pure NoRegexpFlags
3553+ parse t = SomeRegexpFlags <$> parseNEJSON (String <$> T.splitOn "|" t)
3555+instance FromJSON RegexpFlag where
3556+ parseJSON = withText "RegexpFlag" parse
3557+ where parse "ANYSTRING" = pure AnyString
3558+ parse "AUTOMATON" = pure Automaton
3559+ parse "COMPLEMENT" = pure Complement
3560+ parse "EMPTY" = pure Empty
3561+ parse "INTERSECTION" = pure Intersection
3562+ parse "INTERVAL" = pure Interval
3563+ parse f = fail ("Unknown RegexpFlag: " <> show f)
3565+instance ToJSON Term where
3566+ toJSON (Term field value) = object ["term" .= object
3569+instance FromJSON Term where
3570+ parseJSON = withObject "Term" parse
3571+ where parse o = do termObj <- o .: "term"
3572+ case HM.toList termObj of
3573+ [(fn, v)] -> Term fn <$> parseJSON v
3574+ _ -> fail "Expected object with 1 field-named key"
3576+instance ToJSON BoolMatch where
3577+ toJSON (MustMatch term cache) = object ["must" .= term,
3579+ toJSON (MustNotMatch term cache) = object ["must_not" .= term,
3581+ toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
3584+instance FromJSON BoolMatch where
3585+ parseJSON = withObject "BoolMatch" parse
3586+ where parse o = mustMatch `taggedWith` "must"
3587+ <|> mustNotMatch `taggedWith` "must_not"
3588+ <|> shouldMatch `taggedWith` "should"
3589+ where taggedWith parser k = parser =<< o .: k
3590+ mustMatch t = MustMatch t <$> o .:? "_cache" .!= defaultCache
3591+ mustNotMatch t = MustNotMatch t <$> o .:? "_cache" .!= defaultCache
3592+ shouldMatch t = ShouldMatch t <$> o .:? "_cache" .!= defaultCache
3594+instance (FromJSON a) => FromJSON (SearchResult a) where
3595+ parseJSON (Object v) = SearchResult <$>
3597+ v .: "timed_out" <*>
3600+ v .:? "aggregations" <*>
3602+ parseJSON _ = empty
3604+instance (FromJSON a) => FromJSON (SearchHits a) where
3605+ parseJSON (Object v) = SearchHits <$>
3607+ v .: "max_score" <*>
3609+ parseJSON _ = empty
3611+instance (FromJSON a) => FromJSON (Hit a) where
3612+ parseJSON (Object v) = Hit <$>
3617+ v .:? "_source" <*>
3619+ parseJSON _ = empty
3621+instance FromJSON ShardResult where
3622+ parseJSON (Object v) = ShardResult <$>
3624+ v .: "successful" <*>
3626+ parseJSON _ = empty
3629+instance FromJSON DocVersion where
3632+ maybe (fail "DocVersion out of range") return $ mkDocVersion i
3634+-- This insanity is because ES *sometimes* returns Replica/Shard counts as strings
3635+instance FromJSON ReplicaCount where
3636+ parseJSON v = parseAsInt v
3637+ <|> parseAsString v
3638+ where parseAsInt = fmap ReplicaCount . parseJSON
3639+ parseAsString = withText "ReplicaCount" (fmap ReplicaCount . parseReadText)
3641+instance FromJSON ShardCount where
3642+ parseJSON v = parseAsInt v
3643+ <|> parseAsString v
3644+ where parseAsInt = fmap ShardCount . parseJSON
3645+ parseAsString = withText "ShardCount" (fmap ShardCount . parseReadText)
3647+instance Bounded DocVersion where
3648+ minBound = DocVersion 1
3649+ maxBound = DocVersion 9200000000000000000 -- 9.2e+18
3651+instance Enum DocVersion where
3653+ | x /= maxBound = DocVersion (succ $ docVersionNumber x)
3654+ | otherwise = succError "DocVersion"
3656+ | x /= minBound = DocVersion (pred $ docVersionNumber x)
3657+ | otherwise = predError "DocVersion"
3659+ fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
3660+ fromEnum = docVersionNumber
3661+ enumFrom = boundedEnumFrom
3662+ enumFromThen = boundedEnumFromThen
3664+-- | Username type used for HTTP Basic authentication. See 'basicAuthHook'.
3665+newtype EsUsername = EsUsername { esUsername :: Text } deriving (Read, Show, Eq)
3667+-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
3668+newtype EsPassword = EsPassword { esPassword :: Text } deriving (Read, Show, Eq)
3671+data SnapshotRepoSelection = SnapshotRepoList (NonEmpty SnapshotRepoPattern)
3672+ | AllSnapshotRepos deriving (Eq, Generic, Show, Typeable)
3675+-- | Either specifies an exact repo name or one with globs in it,
3676+-- e.g. @RepoPattern "foo*"@ __NOTE__: Patterns are not supported on ES < 1.7
3677+data SnapshotRepoPattern = ExactRepo SnapshotRepoName
3679+ deriving (Eq, Generic, Show, Typeable)
3681+-- | The unique name of a snapshot repository.
3682+newtype SnapshotRepoName = SnapshotRepoName { snapshotRepoName :: Text }
3683+ deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3686+-- | A generic representation of a snapshot repo. This is what gets
3687+-- sent to and parsed from the server. For repo types enabled by
3688+-- plugins that aren't exported by this library, consider making a
3689+-- custom type which implements 'SnapshotRepo'. If it is a common repo
3690+-- type, consider submitting a pull request to have it included in the
3692+data GenericSnapshotRepo = GenericSnapshotRepo {
3693+ gSnapshotRepoName :: SnapshotRepoName
3694+ , gSnapshotRepoType :: SnapshotRepoType
3695+ , gSnapshotRepoSettings :: GenericSnapshotRepoSettings
3696+ } deriving (Eq, Generic, Show, Typeable)
3699+newtype SnapshotRepoType = SnapshotRepoType { snapshotRepoType :: Text }
3700+ deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3703+-- | Opaque representation of snapshot repo settings. Instances of
3704+-- 'SnapshotRepo' will produce this.
3705+newtype GenericSnapshotRepoSettings = GenericSnapshotRepoSettings { gSnapshotRepoSettingsObject :: Object }
3706+ deriving (Eq, Generic, Show, Typeable, ToJSON, FromJSON)
3709+-- | The result of running 'verifySnapshotRepo'. --TODO: more detail once you know what a failure looks like
3710+newtype SnapshotVerification = SnapshotVerification { snapshotNodeVerifications :: [SnapshotNodeVerification] }
3711+ deriving (Eq, Generic, Show, Typeable)
3714+instance FromJSON SnapshotVerification where
3715+ parseJSON = withObject "SnapshotVerification" parse
3719+ SnapshotVerification <$> mapM (uncurry parse') (HM.toList o2)
3720+ parse' rawFullId = withObject "SnapshotNodeVerification" $ \o ->
3721+ SnapshotNodeVerification (FullNodeId rawFullId) <$> o .: "name"
3724+data SnapshotNodeVerification = SnapshotNodeVerification {
3725+ snvFullId :: FullNodeId
3726+ , snvNodeName :: NodeName
3727+ } deriving (Eq, Generic, Show, Typeable)
3730+-- | Unique, automatically-generated name assigned to nodes that are
3731+-- usually returned in node-oriented APIs.
3732+newtype FullNodeId = FullNodeId { fullNodeId :: Text }
3733+ deriving (Eq, Generic, Show, Typeable, FromJSON)
3736+newtype NodeName = NodeName { nodeName :: Text }
3737+ deriving (Eq, Generic, Show, Typeable, FromJSON)
3740+data SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings {
3741+ repoUpdateVerify :: Bool
3742+ -- ^ After creation/update, synchronously check that nodes can
3743+ -- write to this repo. Defaults to True. You may use False if you
3744+ -- need a faster response and plan on verifying manually later
3745+ -- with 'verifySnapshotRepo'.
3746+ } deriving (Eq, Show, Generic, Typeable)
3749+-- | Reasonable defaults for repo creation/update
3751+-- * repoUpdateVerify True
3752+defaultSnapshotRepoUpdateSettings :: SnapshotRepoUpdateSettings
3753+defaultSnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings True
3756+-- | A filesystem-based snapshot repo that ships with elasticsearch.
3757+data FsSnapshotRepo = FsSnapshotRepo {
3758+ fsrName :: SnapshotRepoName
3759+ , fsrLocation :: FilePath
3760+ , fsrCompressMetadata :: Bool
3761+ , fsrChunkSize :: Maybe Bytes
3762+ , fsrMaxRestoreBytesPerSec :: Maybe Bytes
3763+ , fsrMaxSnapshotBytesPerSec :: Maybe Bytes
3764+ } deriving (Eq, Generic, Show, Typeable)
3767+instance SnapshotRepo FsSnapshotRepo where
3768+ toGSnapshotRepo FsSnapshotRepo {..} =
3769+ GenericSnapshotRepo fsrName fsRepoType (GenericSnapshotRepoSettings settings)
3771+ Object settings = object $ [ "location" .= fsrLocation
3772+ , "compress" .= fsrCompressMetadata
3774+ optionalPairs = catMaybes [ ("chunk_size" .=) <$> fsrChunkSize
3775+ , ("max_restore_bytes_per_sec" .=) <$> fsrMaxRestoreBytesPerSec
3776+ , ("max_snapshot_bytes_per_sec" .=) <$> fsrMaxSnapshotBytesPerSec
3778+ fromGSnapshotRepo GenericSnapshotRepo {..}
3779+ | gSnapshotRepoType == fsRepoType = do
3780+ let o = gSnapshotRepoSettingsObject gSnapshotRepoSettings
3782+ FsSnapshotRepo gSnapshotRepoName <$> o .: "location"
3783+ <*> o .:? "compress" .!= False
3784+ <*> o .:? "chunk_size"
3785+ <*> o .:? "max_restore_bytes_per_sec"
3786+ <*> o .:? "max_snapshot_bytes_per_sec"
3787+ | otherwise = Left (RepoTypeMismatch fsRepoType gSnapshotRepoType)
3790+--TODO: test what error case looks like
3791+parseRepo :: Parser a -> Either SnapshotRepoConversionError a
3792+parseRepo parser = case parseEither (const parser) () of
3793+ Left e -> Left (OtherRepoConversionError (T.pack e))
3797+fsRepoType :: SnapshotRepoType
3798+fsRepoType = SnapshotRepoType "fs"
3800+-- | Law: fromGSnapshotRepo (toGSnapshotRepo r) == Right r
3801+class SnapshotRepo r where
3802+ toGSnapshotRepo :: r -> GenericSnapshotRepo
3803+ fromGSnapshotRepo :: GenericSnapshotRepo -> Either SnapshotRepoConversionError r
3806+data SnapshotRepoConversionError = RepoTypeMismatch SnapshotRepoType
3810+ | OtherRepoConversionError Text
3811+ deriving (Show, Eq, Generic, Typeable)
529−instance (FromJSON a) => FromJSON (SearchResult a) where
530− parseJSON (Object v) = SearchResult <$>
532− v .: "timed_out" <*>
535− v .:? "aggregations" <*>
536− v .:? "_scroll_id" <*>
540−newtype ScrollId =
3814+instance Exception SnapshotRepoConversionError
542− deriving (Eq, Show, Ord, ToJSON, FromJSON)