git.iko.soy/typeable/bloodhound
on index-aliases help sign in
3074 lines 126 kB history raw
1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE NoMonomorphismRestriction #-}
8{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE RecordWildCards #-}
10{-# LANGUAGE UndecidableInstances #-}
12-------------------------------------------------------------------------------
13-- |
14-- Module : Database.Bloodhound.Types
15-- Copyright : (C) 2014 Chris Allen
16-- License : BSD-style (see the file LICENSE)
17-- Maintainer : Chris Allen <cma@bitemyapp.com
18-- Stability : provisional
19-- Portability : DeriveGeneric, RecordWildCards
20--
21-- Data types for describing actions and data structures performed to interact
22-- with Elasticsearch. The two main buckets your queries against Elasticsearch
23-- will fall into are 'Query's and 'Filter's. 'Filter's are more like
24-- traditional database constraints and often have preferable performance
25-- properties. 'Query's support human-written textual queries, such as fuzzy
26-- queries.
27-------------------------------------------------------------------------------
31module Database.Bloodhound.Types
32 ( defaultCache
33 , defaultIndexSettings
34 , defaultIndexDocumentSettings
35 , mkSort
36 , showText
37 , unpackId
38 , mkMatchQuery
39 , mkMultiMatchQuery
40 , mkBoolQuery
41 , mkRangeQuery
42 , mkQueryStringQuery
43 , mkAggregations
44 , mkTermsAggregation
45 , mkTermsScriptAggregation
46 , mkDateHistogram
47 , mkDocVersion
48 , docVersionNumber
49 , toTerms
50 , toDateHistogram
51 , omitNulls
52 , BH(..)
53 , runBH
54 , BHEnv(..)
55 , MonadBH(..)
56 , Version(..)
57 , Status(..)
58 , Existence(..)
59 , NullValue(..)
60 , IndexSettings(..)
61 , IndexTemplate(..)
62 , Server(..)
63 , Reply
64 , EsResult(..)
65 , EsResultFound(..)
66 , EsError(..)
67 , IndexAlias(..)
68 , IndexAliasName(..)
69 , IndexAliasAction(..)
70 , IndexAliasCreate(..)
71 , IndexAliasSummary(..)
72 , IndexAliasesSummary(..)
73 , AliasRouting(..)
74 , SearchAliasRouting(..)
75 , IndexAliasRouting(..)
76 , RoutingValue(..)
77 , DocVersion
78 , ExternalDocVersion(..)
79 , VersionControl(..)
80 , DocumentParent(..)
81 , IndexDocumentSettings(..)
82 , Query(..)
83 , Search(..)
84 , SearchType(..)
85 , SearchResult(..)
86 , ScrollId(..)
87 , SearchHits(..)
88 , TrackSortScores
89 , From(..)
90 , Size(..)
91 , Source(..)
92 , PatternOrPatterns(..)
93 , Include(..)
94 , Exclude(..)
95 , Pattern(..)
96 , ShardResult(..)
97 , Hit(..)
98 , Filter(..)
99 , Seminearring(..)
100 , BoolMatch(..)
101 , Term(..)
102 , GeoPoint(..)
103 , GeoBoundingBoxConstraint(..)
104 , GeoBoundingBox(..)
105 , GeoFilterType(..)
106 , Distance(..)
107 , DistanceUnit(..)
108 , DistanceType(..)
109 , DistanceRange(..)
110 , OptimizeBbox(..)
111 , LatLon(..)
112 , RangeValue(..)
113 , RangeExecution(..)
114 , LessThan(..)
115 , LessThanEq(..)
116 , GreaterThan(..)
117 , GreaterThanEq(..)
118 , LessThanD(..)
119 , LessThanEqD(..)
120 , GreaterThanD(..)
121 , GreaterThanEqD(..)
122 , Regexp(..)
123 , RegexpFlags(..)
124 , RegexpFlag(..)
125 , FieldName(..)
126 , Script(..)
127 , IndexName(..)
128 , TemplateName(..)
129 , TemplatePattern(..)
130 , MappingName(..)
131 , DocId(..)
132 , CacheName(..)
133 , CacheKey(..)
134 , BulkOperation(..)
135 , ReplicaCount(..)
136 , ShardCount(..)
137 , Sort
138 , SortMode(..)
139 , SortOrder(..)
140 , SortSpec(..)
141 , DefaultSort(..)
142 , Missing(..)
143 , OpenCloseIndex(..)
144 , Method
145 , Boost(..)
146 , MatchQuery(..)
147 , MultiMatchQuery(..)
148 , BoolQuery(..)
149 , BoostingQuery(..)
150 , CommonTermsQuery(..)
151 , DisMaxQuery(..)
152 , FilteredQuery(..)
153 , FuzzyLikeThisQuery(..)
154 , FuzzyLikeFieldQuery(..)
155 , FuzzyQuery(..)
156 , HasChildQuery(..)
157 , HasParentQuery(..)
158 , IndicesQuery(..)
159 , MoreLikeThisQuery(..)
160 , MoreLikeThisFieldQuery(..)
161 , NestedQuery(..)
162 , PrefixQuery(..)
163 , QueryStringQuery(..)
164 , SimpleQueryStringQuery(..)
165 , RangeQuery(..)
166 , RegexpQuery(..)
167 , QueryString(..)
168 , BooleanOperator(..)
169 , ZeroTermsQuery(..)
170 , CutoffFrequency(..)
171 , Analyzer(..)
172 , MaxExpansions(..)
173 , Lenient(..)
174 , MatchQueryType(..)
175 , MultiMatchQueryType(..)
176 , Tiebreaker(..)
177 , MinimumMatch(..)
178 , DisableCoord(..)
179 , CommonMinimumMatch(..)
180 , MinimumMatchHighLow(..)
181 , PrefixLength(..)
182 , Fuzziness(..)
183 , IgnoreTermFrequency(..)
184 , MaxQueryTerms(..)
185 , ScoreType(..)
186 , Score
187 , Cache
188 , TypeName(..)
189 , BoostTerms(..)
190 , MaxWordLength(..)
191 , MinWordLength(..)
192 , MaxDocFrequency(..)
193 , MinDocFrequency(..)
194 , PhraseSlop(..)
195 , StopWord(..)
196 , QueryPath(..)
197 , MinimumTermFrequency(..)
198 , PercentMatch(..)
199 , FieldDefinition(..)
200 , MappingField(..)
201 , Mapping(..)
202 , AllowLeadingWildcard(..)
203 , LowercaseExpanded(..)
204 , GeneratePhraseQueries(..)
205 , Locale(..)
206 , AnalyzeWildcard(..)
207 , EnablePositionIncrements(..)
208 , SimpleQueryFlag(..)
209 , FieldOrFields(..)
210 , Monoid(..)
211 , ToJSON(..)
212 , Interval(..)
213 , TimeInterval(..)
214 , ExecutionHint(..)
215 , CollectionMode(..)
216 , TermOrder(..)
217 , TermInclusion(..)
219 , Aggregation(..)
220 , Aggregations
221 , AggregationResults
222 , Bucket(..)
223 , BucketAggregation(..)
224 , TermsAggregation(..)
225 , ValueCountAggregation(..)
226 , FilterAggregation(..)
227 , DateHistogramAggregation(..)
229 , Highlights(..)
230 , FieldHighlight(..)
231 , HighlightSettings(..)
232 , PlainHighlight(..)
233 , PostingsHighlight(..)
234 , FastVectorHighlight(..)
235 , CommonHighlight(..)
236 , NonPostings(..)
237 , HighlightEncoder(..)
238 , HighlightTag(..)
239 , HitHighlight
241 , TermsResult(..)
242 , DateHistogramResult(..)
243 ) where
245import Control.Applicative
246import Control.Monad.Catch
247import Control.Monad.Except
248import Control.Monad.Reader
249import Control.Monad.State
250import Control.Monad.Writer
251import Data.Aeson
252import Data.Aeson.Types (Pair, Parser, emptyObject,
253 parseMaybe)
254import qualified Data.ByteString.Lazy.Char8 as L
255import Data.Char
256import Data.Hashable (Hashable)
257import qualified Data.HashMap.Strict as HM
258import Data.List (foldl', nub)
259import Data.List.NonEmpty (NonEmpty (..), toList)
260import qualified Data.Map.Strict as M
261import Data.Maybe
262import Data.Text (Text)
263import qualified Data.Text as T
264import Data.Time.Clock (UTCTime)
265import qualified Data.Traversable as DT
266import Data.Typeable (Typeable)
267import qualified Data.Vector as V
268import GHC.Enum
269import GHC.Generics (Generic)
270import Network.HTTP.Client
271import qualified Network.HTTP.Types.Method as NHTM
273import Database.Bloodhound.Types.Class
275-- $setup
276-- >>> :set -XOverloadedStrings
277-- >>> import Database.Bloodhound
278-- >>> let testServer = (Server "http://localhost:9200")
279-- >>> let testIndex = IndexName "twitter"
280-- >>> let testMapping = MappingName "tweet"
281-- >>> let defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
283-- defaultIndexSettings is exported by Database.Bloodhound as well
284-- no trailing slashes in servers, library handles building the path.
286{-| Common environment for Elasticsearch calls. Connections will be
287 pipelined according to the provided HTTP connection manager.
288-}
289data BHEnv = BHEnv { bhServer :: Server
290 , bhManager :: Manager
291 }
293{-| All API calls to Elasticsearch operate within
294 MonadBH. The idea is that it can be easily embedded in your
295 own monad transformer stack. A default instance for a ReaderT and
296 alias 'BH' is provided for the simple case.
297-}
298class (Functor m, Applicative m, MonadIO m) => MonadBH m where
299 getBHEnv :: m BHEnv
301newtype BH m a = BH {
302 unBH :: ReaderT BHEnv m a
303 } deriving ( Functor
304 , Applicative
305 , Monad
306 , MonadIO
307 , MonadState s
308 , MonadWriter w
309 , MonadError e
310 , Alternative
311 , MonadPlus
312 , MonadFix
313 , MonadThrow
314 , MonadCatch
315 , MonadMask)
317instance MonadTrans BH where
318 lift = BH . lift
320instance (MonadReader r m) => MonadReader r (BH m) where
321 ask = lift ask
322 local f (BH (ReaderT m)) = BH $ ReaderT $ \r ->
323 local f (m r)
325instance (Functor m, Applicative m, MonadIO m) => MonadBH (BH m) where
326 getBHEnv = BH getBHEnv
329instance (Functor m, Applicative m, MonadIO m) => MonadBH (ReaderT BHEnv m) where
330 getBHEnv = ask
332runBH :: BHEnv -> BH m a -> m a
333runBH e f = runReaderT (unBH f) e
335{-| 'Version' is embedded in 'Status' -}
336data Version = Version { number :: Text
337 , build_hash :: Text
338 , build_timestamp :: UTCTime
339 , build_snapshot :: Bool
340 , lucene_version :: Text } deriving (Eq, Show, Generic, Typeable)
342{-| 'Status' is a data type for describing the JSON body returned by
343 Elasticsearch when you query its status. This was deprecated in 1.2.0.
345 <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-status.html#indices-status>
346-}
348data Status = Status { ok :: Maybe Bool
349 , status :: Int
350 , name :: Text
351 , version :: Version
352 , tagline :: Text } deriving (Eq, Show)
354{-| 'IndexSettings' is used to configure the shards and replicas when you create
355 an Elasticsearch Index.
357 <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-create-index.html>
358-}
360data IndexSettings =
361 IndexSettings { indexShards :: ShardCount
362 , indexReplicas :: ReplicaCount } deriving (Eq, Show)
364{-| 'defaultIndexSettings' is an 'IndexSettings' with 3 shards and 2 replicas. -}
365defaultIndexSettings :: IndexSettings
366defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
368{-| 'Reply' and 'Method' are type synonyms from 'Network.HTTP.Types.Method.Method' -}
369type Reply = Network.HTTP.Client.Response L.ByteString
370type Method = NHTM.Method
372{-| 'OpenCloseIndex' is a sum type for opening and closing indices.
374 <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-open-close.html>
375-}
376data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Show)
378data FieldType = GeoPointType
379 | GeoShapeType
380 | FloatType
381 | IntegerType
382 | LongType
383 | ShortType
384 | ByteType deriving (Eq, Show)
386data FieldDefinition =
387 FieldDefinition { fieldType :: FieldType } deriving (Eq, Show)
389{-| An 'IndexTemplate' defines a template that will automatically be
390 applied to new indices created. The templates include both
391 'IndexSettings' and mappings, and a simple 'TemplatePattern' that
392 controls if the template will be applied to the index created.
393 Specify mappings as follows: @[toJSON TweetMapping, ...]@
395 https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html
396-}
397data IndexTemplate =
398 IndexTemplate { templatePattern :: TemplatePattern
399 , templateSettings :: Maybe IndexSettings
400 , templateMappings :: [Value]
401 }
403data MappingField =
404 MappingField { mappingFieldName :: FieldName
405 , fieldDefinition :: FieldDefinition } deriving (Eq, Show)
407{-| Support for type reification of 'Mapping's is currently incomplete, for
408 now the mapping API verbiage expects a 'ToJSON'able blob.
410 Indexes have mappings, mappings are schemas for the documents contained in the
411 index. I'd recommend having only one mapping per index, always having a mapping,
412 and keeping different kinds of documents separated if possible.
413-}
414data Mapping = Mapping { typeName :: TypeName
415 , mappingFields :: [MappingField] } deriving (Eq, Show)
417{-| 'BulkOperation' is a sum type for expressing the four kinds of bulk
418 operation index, create, delete, and update. 'BulkIndex' behaves like an
419 "upsert", 'BulkCreate' will fail if a document already exists at the DocId.
421 <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-bulk.html#docs-bulk>
422-}
423data BulkOperation =
424 BulkIndex IndexName MappingName DocId Value
425 | BulkCreate IndexName MappingName DocId Value
426 | BulkDelete IndexName MappingName DocId
427 | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Show)
429{-| 'EsResult' describes the standard wrapper JSON document that you see in
430 successful Elasticsearch lookups or lookups that couldn't find the document.
431-}
432data EsResult a = EsResult { _index :: Text
433 , _type :: Text
434 , _id :: Text
435 , foundResult :: Maybe (EsResultFound a)} deriving (Eq, Show)
437{-| 'EsResultFound' contains the document and its metadata inside of an
438 'EsResult' when the document was successfully found.
439-}
440data EsResultFound a = EsResultFound { _version :: DocVersion
441 , _source :: a } deriving (Eq, Show)
443{-| 'EsError' is the generic type that will be returned when there was a
444 problem. If you can't parse the expected response, its a good idea to
445 try parsing this.
446-}
447data EsError = EsError { errorStatus :: Int
448 , errorMessage :: Text } deriving (Eq, Show)
450data IndexAlias = IndexAlias { srcIndex :: IndexName
451 , indexAlias :: IndexAliasName } deriving (Eq, Show)
453newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Show, ToJSON)
455data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
456 | RemoveAlias IndexAlias deriving (Show, Eq, Typeable)
458data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
459 , aliasCreateFilter :: Maybe Filter}
460 deriving (Show, Eq, Typeable)
462data AliasRouting = AllAliasRouting RoutingValue
463 | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
464 deriving (Show, Eq, Typeable)
466newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Show, Eq, Typeable)
468newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Show, Eq, ToJSON, FromJSON, Typeable)
470newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Show, Eq, ToJSON, FromJSON, Typeable)
472newtype IndexAliasesSummary = IndexAliasesSummary { indexAliasesSummary :: [IndexAliasSummary] } deriving (Show, Eq, Typeable)
474{-| 'IndexAliasSummary' is a summary of an index alias configured for a server. -}
475data IndexAliasSummary = IndexAliasSummary { indexAliasSummaryAlias :: IndexAlias
476 , indexAliasSummaryCreate :: IndexAliasCreate} deriving (Show, Eq)
478{-| 'DocVersion' is an integer version number for a document between 1
479and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
480-}
481newtype DocVersion = DocVersion {
482 docVersionNumber :: Int
483 } deriving (Eq, Show, Ord, ToJSON)
485-- | Smart constructor for in-range doc version
486mkDocVersion :: Int -> Maybe DocVersion
487mkDocVersion i
488 | i >= (docVersionNumber minBound) && i <= (docVersionNumber maxBound) =
489 Just $ DocVersion i
490 | otherwise = Nothing
493{-| 'ExternalDocVersion' is a convenience wrapper if your code uses its
494own version numbers instead of ones from ES.
495-}
496newtype ExternalDocVersion = ExternalDocVersion DocVersion
497 deriving (Eq, Show, Ord, Bounded, Enum, ToJSON)
499{-| 'VersionControl' is specified when indexing documents as a
500optimistic concurrency control.
501-}
502data VersionControl = NoVersionControl
503 -- ^ Don't send a version. This is a pure overwrite.
504 | InternalVersion DocVersion
505 -- ^ Use the default ES versioning scheme. Only
506 -- index the document if the version is the same
507 -- as the one specified. Only applicable to
508 -- updates, as you should be getting Version from
509 -- a search result.
510 | ExternalGT ExternalDocVersion
511 -- ^ Use your own version numbering. Only index
512 -- the document if the version is strictly higher
513 -- OR the document doesn't exist. The given
514 -- version will be used as the new version number
515 -- for the stored document. N.B. All updates must
516 -- increment this number, meaning there is some
517 -- global, external ordering of updates.
518 | ExternalGTE ExternalDocVersion
519 -- ^ Use your own version numbering. Only index
520 -- the document if the version is equal or higher
521 -- than the stored version. Will succeed if there
522 -- is no existing document. The given version will
523 -- be used as the new version number for the
524 -- stored document. Use with care, as this could
525 -- result in data loss.
526 | ForceVersion ExternalDocVersion
527 -- ^ The document will always be indexed and the
528 -- given version will be the new version. This is
529 -- typically used for correcting errors. Use with
530 -- care, as this could result in data loss.
531 deriving (Show, Eq, Ord)
533{-| 'DocumentParent' is used to specify a parent document.
534-}
535newtype DocumentParent = DocumentParent DocId
536 deriving (Eq, Show)
538{-| 'IndexDocumentSettings' are special settings supplied when indexing
539a document. For the best backwards compatiblity when new fields are
540added, you should probably prefer to start with 'defaultIndexDocumentSettings'
541-}
542data IndexDocumentSettings =
543 IndexDocumentSettings { idsVersionControl :: VersionControl
544 , idsParent :: Maybe DocumentParent
545 } deriving (Eq, Show)
547{-| Reasonable default settings. Chooses no version control and no parent.
548-}
549defaultIndexDocumentSettings :: IndexDocumentSettings
550defaultIndexDocumentSettings = IndexDocumentSettings NoVersionControl Nothing
552{-| 'Sort' is a synonym for a list of 'SortSpec's. Sort behavior is order
553 dependent with later sorts acting as tie-breakers for earlier sorts.
554-}
555type Sort = [SortSpec]
557{-| The two main kinds of 'SortSpec' are 'DefaultSortSpec' and
558 'GeoDistanceSortSpec'. The latter takes a 'SortOrder', 'GeoPoint', and
559 'DistanceUnit' to express "nearness" to a single geographical point as a
560 sort specification.
562<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
563-}
564data SortSpec = DefaultSortSpec DefaultSort
565 | GeoDistanceSortSpec SortOrder GeoPoint DistanceUnit deriving (Eq, Show)
567{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
568 'mkSort' convenience function for when you want to specify only the most
569 common parameters.
571<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
572-}
573data DefaultSort =
574 DefaultSort { sortFieldName :: FieldName
575 , sortOrder :: SortOrder
576 -- default False
577 , ignoreUnmapped :: Bool
578 , sortMode :: Maybe SortMode
579 , missingSort :: Maybe Missing
580 , nestedFilter :: Maybe Filter } deriving (Eq, Show)
582{-| 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get
583 encoded into "asc" or "desc" when turned into JSON.
585<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
586-}
587data SortOrder = Ascending
588 | Descending deriving (Eq, Show)
590{-| 'Missing' prescribes how to handle missing fields. A missing field can be
591 sorted last, first, or using a custom value as a substitute.
593<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_missing_values>
594-}
595data Missing = LastMissing
596 | FirstMissing
597 | CustomMissing Text deriving (Eq, Show)
599{-| 'SortMode' prescribes how to handle sorting array/multi-valued fields.
601http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_mode_option
602-}
603data SortMode = SortMin
604 | SortMax
605 | SortSum
606 | SortAvg deriving (Eq, Show)
608{-| 'mkSort' defaults everything but the 'FieldName' and the 'SortOrder' so
609 that you can concisely describe the usual kind of 'SortSpec's you want.
610-}
611mkSort :: FieldName -> SortOrder -> DefaultSort
612mkSort fieldName sOrder = DefaultSort fieldName sOrder False Nothing Nothing Nothing
614{-| 'Cache' is for telling ES whether it should cache a 'Filter' not.
615 'Query's cannot be cached.
616-}
617type Cache = Bool -- caching on/off
618defaultCache :: Cache
619defaultCache = False
621{-| 'PrefixValue' is used in 'PrefixQuery' as the main query component.
622-}
623type PrefixValue = Text
625{-| 'BooleanOperator' is the usual And/Or operators with an ES compatible
626 JSON encoding baked in. Used all over the place.
627-}
628data BooleanOperator = And | Or deriving (Eq, Show, Typeable)
630{-| 'ShardCount' is part of 'IndexSettings'
631-}
632newtype ShardCount = ShardCount Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
634{-| 'ReplicaCount' is part of 'IndexSettings'
635-}
636newtype ReplicaCount = ReplicaCount Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
638{-| 'Server' is used with the client functions to point at the ES instance
639-}
640newtype Server = Server Text deriving (Eq, Show)
642{-| 'IndexName' is used to describe which index to query/create/delete
643-}
644newtype IndexName = IndexName Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
646{-| 'TemplateName' is used to describe which template to query/create/delete
647-}
648newtype TemplateName = TemplateName Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
650{-| 'TemplatePattern' represents a pattern which is matched against index names
651-}
652newtype TemplatePattern = TemplatePattern Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
654{-| 'MappingName' is part of mappings which are how ES describes and schematizes
655 the data in the indices.
656-}
657newtype MappingName = MappingName Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
659{-| 'DocId' is a generic wrapper value for expressing unique Document IDs.
660 Can be set by the user or created by ES itself. Often used in client
661 functions for poking at specific documents.
662-}
663newtype DocId = DocId Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
665{-| 'QueryString' is used to wrap query text bodies, be they human written or not.
666-}
667newtype QueryString = QueryString Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
669{-| 'FieldName' is used all over the place wherever a specific field within
670 a document needs to be specified, usually in 'Query's or 'Filter's.
671-}
672newtype FieldName = FieldName Text deriving (Eq, Show, ToJSON, FromJSON, Typeable)
675{-| 'Script' is often used in place of 'FieldName' to specify more
676complex ways of extracting a value from a document.
677-}
678newtype Script = Script { scriptText :: Text } deriving (Eq, Show)
680{-| 'CacheName' is used in 'RegexpFilter' for describing the
681 'CacheKey' keyed caching behavior.
682-}
683newtype CacheName = CacheName Text deriving (Eq, Show, ToJSON, FromJSON, Typeable)
685{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
686-}
687newtype CacheKey =
688 CacheKey Text deriving (Eq, Show, ToJSON, FromJSON, Typeable)
689newtype Existence =
690 Existence Bool deriving (Eq, Show, ToJSON, FromJSON, Typeable)
691newtype NullValue =
692 NullValue Bool deriving (Eq, Show, ToJSON, FromJSON, Typeable)
693newtype CutoffFrequency =
694 CutoffFrequency Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
695newtype Analyzer =
696 Analyzer Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
697newtype MaxExpansions =
698 MaxExpansions Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
700{-| 'Lenient', if set to true, will cause format based failures to be
701 ignored. I don't know what the bloody default is, Elasticsearch
702 documentation didn't say what it was. Let me know if you figure it out.
703-}
704newtype Lenient =
705 Lenient Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
706newtype Tiebreaker =
707 Tiebreaker Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
708newtype Boost =
709 Boost Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
710newtype BoostTerms =
711 BoostTerms Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
713{-| 'MinimumMatch' controls how many should clauses in the bool query should
714 match. Can be an absolute value (2) or a percentage (30%) or a
715 combination of both.
716-}
717newtype MinimumMatch =
718 MinimumMatch Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
719newtype DisableCoord =
720 DisableCoord Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
721newtype IgnoreTermFrequency =
722 IgnoreTermFrequency Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
723newtype MinimumTermFrequency =
724 MinimumTermFrequency Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
725newtype MaxQueryTerms =
726 MaxQueryTerms Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
727newtype Fuzziness =
728 Fuzziness Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
730{-| 'PrefixLength' is the prefix length used in queries, defaults to 0. -}
731newtype PrefixLength =
732 PrefixLength Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
733newtype TypeName =
734 TypeName Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
735newtype PercentMatch =
736 PercentMatch Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
737newtype StopWord =
738 StopWord Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
739newtype QueryPath =
740 QueryPath Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
742{-| Allowing a wildcard at the beginning of a word (eg "*ing") is particularly
743 heavy, because all terms in the index need to be examined, just in case
744 they match. Leading wildcards can be disabled by setting
745 'AllowLeadingWildcard' to false. -}
746newtype AllowLeadingWildcard =
747 AllowLeadingWildcard Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
748newtype LowercaseExpanded =
749 LowercaseExpanded Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
750newtype EnablePositionIncrements =
751 EnablePositionIncrements Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
753{-| By default, wildcard terms in a query are not analyzed.
754 Setting 'AnalyzeWildcard' to true enables best-effort analysis.
755-}
756newtype AnalyzeWildcard = AnalyzeWildcard Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
758{-| 'GeneratePhraseQueries' defaults to false.
759-}
760newtype GeneratePhraseQueries =
761 GeneratePhraseQueries Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
763{-| 'Locale' is used for string conversions - defaults to ROOT.
764-}
765newtype Locale = Locale Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
766newtype MaxWordLength = MaxWordLength Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
767newtype MinWordLength = MinWordLength Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
769{-| 'PhraseSlop' sets the default slop for phrases, 0 means exact
770 phrase matches. Default is 0.
771-}
772newtype PhraseSlop = PhraseSlop Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
773newtype MinDocFrequency = MinDocFrequency Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
774newtype MaxDocFrequency = MaxDocFrequency Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
776{-| 'unpackId' is a silly convenience function that gets used once.
777-}
778unpackId :: DocId -> Text
779unpackId (DocId docId) = docId
781type TrackSortScores = Bool
782newtype From = From Int deriving (Eq, Show, ToJSON)
783newtype Size = Size Int deriving (Eq, Show, ToJSON)
785data Search = Search { queryBody :: Maybe Query
786 , filterBody :: Maybe Filter
787 , sortBody :: Maybe Sort
788 , aggBody :: Maybe Aggregations
789 , highlight :: Maybe Highlights
790 -- default False
791 , trackSortScores :: TrackSortScores
792 , from :: From
793 , size :: Size
794 , searchType :: SearchType
795 , fields :: Maybe [FieldName]
796 , source :: Maybe Source } deriving (Eq, Show)
798data SearchType = SearchTypeQueryThenFetch
799 | SearchTypeDfsQueryThenFetch
800 | SearchTypeCount
801 | SearchTypeScan
802 | SearchTypeQueryAndFetch
803 | SearchTypeDfsQueryAndFetch
804 deriving (Eq, Show)
806data Source =
807 NoSource
808 | SourcePatterns PatternOrPatterns
809 | SourceIncludeExclude Include Exclude
810 deriving (Show, Eq)
812data PatternOrPatterns = PopPattern Pattern
813 | PopPatterns [Pattern] deriving (Eq, Show)
815data Include = Include [Pattern] deriving (Eq, Show)
816data Exclude = Exclude [Pattern] deriving (Eq, Show)
818newtype Pattern = Pattern Text deriving (Eq, Show)
820data Highlights = Highlights { globalsettings :: Maybe HighlightSettings
821 , highlightFields :: [FieldHighlight]
822 } deriving (Show, Eq)
824data FieldHighlight = FieldHighlight FieldName (Maybe HighlightSettings)
825 deriving (Show, Eq)
828data HighlightSettings = Plain PlainHighlight
829 | Postings PostingsHighlight
830 | FastVector FastVectorHighlight
831 deriving (Show, Eq)
832data PlainHighlight =
833 PlainHighlight { plainCommon :: Maybe CommonHighlight
834 , plainNonPost :: Maybe NonPostings } deriving (Show, Eq)
836 -- This requires that index_options are set to 'offset' in the mapping.
837data PostingsHighlight = PostingsHighlight (Maybe CommonHighlight) deriving (Show, Eq)
839-- This requires that term_vector is set to 'with_positions_offsets' in the mapping.
840data FastVectorHighlight =
841 FastVectorHighlight { fvCommon :: Maybe CommonHighlight
842 , fvNonPostSettings :: Maybe NonPostings
843 , boundaryChars :: Maybe Text
844 , boundaryMaxScan :: Maybe Int
845 , fragmentOffset :: Maybe Int
846 , matchedFields :: [Text]
847 , phraseLimit :: Maybe Int
848 } deriving (Show, Eq)
850data CommonHighlight =
851 CommonHighlight { order :: Maybe Text
852 , forceSource :: Maybe Bool
853 , tag :: Maybe HighlightTag
854 , encoder :: Maybe HighlightEncoder
855 , noMatchSize :: Maybe Int
856 , highlightQuery :: Maybe Query
857 , requireFieldMatch :: Maybe Bool
858 } deriving (Show, Eq)
860-- Settings that are only applicable to FastVector and Plain highlighters.
861data NonPostings =
862 NonPostings { fragmentSize :: Maybe Int
863 , numberOfFragments :: Maybe Int} deriving (Show, Eq)
865data HighlightEncoder = DefaultEncoder
866 | HTMLEncoder
867 deriving (Show, Eq)
869-- NOTE: Should the tags use some kind of HTML type, rather than Text?
870data HighlightTag = TagSchema Text
871 | CustomTags ([Text], [Text]) -- Only uses more than the first value in the lists if fvh
872 deriving (Show, Eq)
875data Query =
876 TermQuery Term (Maybe Boost)
877 | TermsQuery Text (NonEmpty Text)
878 | QueryMatchQuery MatchQuery
879 | QueryMultiMatchQuery MultiMatchQuery
880 | QueryBoolQuery BoolQuery
881 | QueryBoostingQuery BoostingQuery
882 | QueryCommonTermsQuery CommonTermsQuery
883 | ConstantScoreFilter Filter Boost
884 | ConstantScoreQuery Query Boost
885 | QueryDisMaxQuery DisMaxQuery
886 | QueryFilteredQuery FilteredQuery
887 | QueryFuzzyLikeThisQuery FuzzyLikeThisQuery
888 | QueryFuzzyLikeFieldQuery FuzzyLikeFieldQuery
889 | QueryFuzzyQuery FuzzyQuery
890 | QueryHasChildQuery HasChildQuery
891 | QueryHasParentQuery HasParentQuery
892 | IdsQuery MappingName [DocId]
893 | QueryIndicesQuery IndicesQuery
894 | MatchAllQuery (Maybe Boost)
895 | QueryMoreLikeThisQuery MoreLikeThisQuery
896 | QueryMoreLikeThisFieldQuery MoreLikeThisFieldQuery
897 | QueryNestedQuery NestedQuery
898 | QueryPrefixQuery PrefixQuery
899 | QueryQueryStringQuery QueryStringQuery
900 | QuerySimpleQueryStringQuery SimpleQueryStringQuery
901 | QueryRangeQuery RangeQuery
902 | QueryRegexpQuery RegexpQuery
903 deriving (Eq, Show, Typeable)
905data RegexpQuery =
906 RegexpQuery { regexpQueryField :: FieldName
907 , regexpQuery :: Regexp
908 , regexpQueryFlags :: RegexpFlags
909 , regexpQueryBoost :: Maybe Boost
910 } deriving (Eq, Show, Typeable)
912data RangeQuery =
913 RangeQuery { rangeQueryField :: FieldName
914 , rangeQueryRange :: RangeValue
915 , rangeQueryBoost :: Boost } deriving (Eq, Show, Typeable)
917mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
918mkRangeQuery f r = RangeQuery f r (Boost 1.0)
920data SimpleQueryStringQuery =
921 SimpleQueryStringQuery
922 { simpleQueryStringQuery :: QueryString
923 , simpleQueryStringField :: Maybe FieldOrFields
924 , simpleQueryStringOperator :: Maybe BooleanOperator
925 , simpleQueryStringAnalyzer :: Maybe Analyzer
926 , simpleQueryStringFlags :: Maybe (NonEmpty SimpleQueryFlag)
927 , simpleQueryStringLowercaseExpanded :: Maybe LowercaseExpanded
928 , simpleQueryStringLocale :: Maybe Locale
929 } deriving (Eq, Show, Typeable)
931data SimpleQueryFlag =
932 SimpleQueryAll
933 | SimpleQueryNone
934 | SimpleQueryAnd
935 | SimpleQueryOr
936 | SimpleQueryPrefix
937 | SimpleQueryPhrase
938 | SimpleQueryPrecedence
939 | SimpleQueryEscape
940 | SimpleQueryWhitespace
941 | SimpleQueryFuzzy
942 | SimpleQueryNear
943 | SimpleQuerySlop deriving (Eq, Show, Typeable)
945-- use_dis_max and tie_breaker when fields are plural?
946data QueryStringQuery =
947 QueryStringQuery
948 { queryStringQuery :: QueryString
949 , queryStringDefaultField :: Maybe FieldName
950 , queryStringOperator :: Maybe BooleanOperator
951 , queryStringAnalyzer :: Maybe Analyzer
952 , queryStringAllowLeadingWildcard :: Maybe AllowLeadingWildcard
953 , queryStringLowercaseExpanded :: Maybe LowercaseExpanded
954 , queryStringEnablePositionIncrements :: Maybe EnablePositionIncrements
955 , queryStringFuzzyMaxExpansions :: Maybe MaxExpansions
956 , queryStringFuzziness :: Maybe Fuzziness
957 , queryStringFuzzyPrefixLength :: Maybe PrefixLength
958 , queryStringPhraseSlop :: Maybe PhraseSlop
959 , queryStringBoost :: Maybe Boost
960 , queryStringAnalyzeWildcard :: Maybe AnalyzeWildcard
961 , queryStringGeneratePhraseQueries :: Maybe GeneratePhraseQueries
962 , queryStringMinimumShouldMatch :: Maybe MinimumMatch
963 , queryStringLenient :: Maybe Lenient
964 , queryStringLocale :: Maybe Locale
965 } deriving (Eq, Show, Typeable)
967mkQueryStringQuery :: QueryString -> QueryStringQuery
968mkQueryStringQuery qs =
969 QueryStringQuery qs Nothing Nothing
970 Nothing Nothing Nothing Nothing
971 Nothing Nothing Nothing Nothing
972 Nothing Nothing Nothing Nothing
973 Nothing Nothing
975data FieldOrFields = FofField FieldName
976 | FofFields (NonEmpty FieldName) deriving (Eq, Show, Typeable)
978data PrefixQuery =
979 PrefixQuery
980 { prefixQueryField :: FieldName
981 , prefixQueryPrefixValue :: Text
982 , prefixQueryBoost :: Maybe Boost } deriving (Eq, Show, Typeable)
984data NestedQuery =
985 NestedQuery
986 { nestedQueryPath :: QueryPath
987 , nestedQueryScoreType :: ScoreType
988 , nestedQuery :: Query } deriving (Eq, Show, Typeable)
990data MoreLikeThisFieldQuery =
991 MoreLikeThisFieldQuery
992 { moreLikeThisFieldText :: Text
993 , moreLikeThisFieldFields :: FieldName
994 -- default 0.3 (30%)
995 , moreLikeThisFieldPercentMatch :: Maybe PercentMatch
996 , moreLikeThisFieldMinimumTermFreq :: Maybe MinimumTermFrequency
997 , moreLikeThisFieldMaxQueryTerms :: Maybe MaxQueryTerms
998 , moreLikeThisFieldStopWords :: Maybe (NonEmpty StopWord)
999 , moreLikeThisFieldMinDocFrequency :: Maybe MinDocFrequency
1000 , moreLikeThisFieldMaxDocFrequency :: Maybe MaxDocFrequency
1001 , moreLikeThisFieldMinWordLength :: Maybe MinWordLength
1002 , moreLikeThisFieldMaxWordLength :: Maybe MaxWordLength
1003 , moreLikeThisFieldBoostTerms :: Maybe BoostTerms
1004 , moreLikeThisFieldBoost :: Maybe Boost
1005 , moreLikeThisFieldAnalyzer :: Maybe Analyzer
1006 } deriving (Eq, Show, Typeable)
1008data MoreLikeThisQuery =
1009 MoreLikeThisQuery
1010 { moreLikeThisText :: Text
1011 , moreLikeThisFields :: Maybe (NonEmpty FieldName)
1012 -- default 0.3 (30%)
1013 , moreLikeThisPercentMatch :: Maybe PercentMatch
1014 , moreLikeThisMinimumTermFreq :: Maybe MinimumTermFrequency
1015 , moreLikeThisMaxQueryTerms :: Maybe MaxQueryTerms
1016 , moreLikeThisStopWords :: Maybe (NonEmpty StopWord)
1017 , moreLikeThisMinDocFrequency :: Maybe MinDocFrequency
1018 , moreLikeThisMaxDocFrequency :: Maybe MaxDocFrequency
1019 , moreLikeThisMinWordLength :: Maybe MinWordLength
1020 , moreLikeThisMaxWordLength :: Maybe MaxWordLength
1021 , moreLikeThisBoostTerms :: Maybe BoostTerms
1022 , moreLikeThisBoost :: Maybe Boost
1023 , moreLikeThisAnalyzer :: Maybe Analyzer
1024 } deriving (Eq, Show, Typeable)
1026data IndicesQuery =
1027 IndicesQuery
1028 { indicesQueryIndices :: [IndexName]
1029 , indicesQuery :: Query
1030 -- default "all"
1031 , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Show, Typeable)
1033data HasParentQuery =
1034 HasParentQuery
1035 { hasParentQueryType :: TypeName
1036 , hasParentQuery :: Query
1037 , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Show, Typeable)
1039data HasChildQuery =
1040 HasChildQuery
1041 { hasChildQueryType :: TypeName
1042 , hasChildQuery :: Query
1043 , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Show, Typeable)
1045data ScoreType =
1046 ScoreTypeMax
1047 | ScoreTypeSum
1048 | ScoreTypeAvg
1049 | ScoreTypeNone deriving (Eq, Show, Typeable)
1051data FuzzyQuery =
1052 FuzzyQuery { fuzzyQueryField :: FieldName
1053 , fuzzyQueryValue :: Text
1054 , fuzzyQueryPrefixLength :: PrefixLength
1055 , fuzzyQueryMaxExpansions :: MaxExpansions
1056 , fuzzyQueryFuzziness :: Fuzziness
1057 , fuzzyQueryBoost :: Maybe Boost
1058 } deriving (Eq, Show, Typeable)
1060data FuzzyLikeFieldQuery =
1061 FuzzyLikeFieldQuery
1062 { fuzzyLikeField :: FieldName
1063 -- anaphora is good for the soul.
1064 , fuzzyLikeFieldText :: Text
1065 , fuzzyLikeFieldMaxQueryTerms :: MaxQueryTerms
1066 , fuzzyLikeFieldIgnoreTermFrequency :: IgnoreTermFrequency
1067 , fuzzyLikeFieldFuzziness :: Fuzziness
1068 , fuzzyLikeFieldPrefixLength :: PrefixLength
1069 , fuzzyLikeFieldBoost :: Boost
1070 , fuzzyLikeFieldAnalyzer :: Maybe Analyzer
1071 } deriving (Eq, Show, Typeable)
1073data FuzzyLikeThisQuery =
1074 FuzzyLikeThisQuery
1075 { fuzzyLikeFields :: [FieldName]
1076 , fuzzyLikeText :: Text
1077 , fuzzyLikeMaxQueryTerms :: MaxQueryTerms
1078 , fuzzyLikeIgnoreTermFrequency :: IgnoreTermFrequency
1079 , fuzzyLikeFuzziness :: Fuzziness
1080 , fuzzyLikePrefixLength :: PrefixLength
1081 , fuzzyLikeBoost :: Boost
1082 , fuzzyLikeAnalyzer :: Maybe Analyzer
1083 } deriving (Eq, Show, Typeable)
1085data FilteredQuery =
1086 FilteredQuery
1087 { filteredQuery :: Query
1088 , filteredFilter :: Filter } deriving (Eq, Show, Typeable)
1090data DisMaxQuery =
1091 DisMaxQuery { disMaxQueries :: [Query]
1092 -- default 0.0
1093 , disMaxTiebreaker :: Tiebreaker
1094 , disMaxBoost :: Maybe Boost
1095 } deriving (Eq, Show, Typeable)
1097data MatchQuery =
1098 MatchQuery { matchQueryField :: FieldName
1099 , matchQueryQueryString :: QueryString
1100 , matchQueryOperator :: BooleanOperator
1101 , matchQueryZeroTerms :: ZeroTermsQuery
1102 , matchQueryCutoffFrequency :: Maybe CutoffFrequency
1103 , matchQueryMatchType :: Maybe MatchQueryType
1104 , matchQueryAnalyzer :: Maybe Analyzer
1105 , matchQueryMaxExpansions :: Maybe MaxExpansions
1106 , matchQueryLenient :: Maybe Lenient
1107 , matchQueryBoost :: Maybe Boost } deriving (Eq, Show, Typeable)
1109{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
1110 enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
1112mkMatchQuery :: FieldName -> QueryString -> MatchQuery
1113mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1115data MatchQueryType =
1116 MatchPhrase
1117 | MatchPhrasePrefix deriving (Eq, Show, Typeable)
1119data MultiMatchQuery =
1120 MultiMatchQuery { multiMatchQueryFields :: [FieldName]
1121 , multiMatchQueryString :: QueryString
1122 , multiMatchQueryOperator :: BooleanOperator
1123 , multiMatchQueryZeroTerms :: ZeroTermsQuery
1124 , multiMatchQueryTiebreaker :: Maybe Tiebreaker
1125 , multiMatchQueryType :: Maybe MultiMatchQueryType
1126 , multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency
1127 , multiMatchQueryAnalyzer :: Maybe Analyzer
1128 , multiMatchQueryMaxExpansions :: Maybe MaxExpansions
1129 , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Show, Typeable)
1131{-| 'mkMultiMatchQuery' is a convenience function that defaults the less common parameters,
1132 enabling you to provide only the list of 'FieldName's and 'QueryString' to
1133 make a 'MultiMatchQuery'.
1136mkMultiMatchQuery :: [FieldName] -> QueryString -> MultiMatchQuery
1137mkMultiMatchQuery matchFields query =
1138 MultiMatchQuery matchFields query
1139 Or ZeroTermsNone Nothing Nothing Nothing Nothing Nothing Nothing
1141data MultiMatchQueryType =
1142 MultiMatchBestFields
1143 | MultiMatchMostFields
1144 | MultiMatchCrossFields
1145 | MultiMatchPhrase
1146 | MultiMatchPhrasePrefix deriving (Eq, Show, Typeable)
1148data BoolQuery =
1149 BoolQuery { boolQueryMustMatch :: [Query]
1150 , boolQueryMustNotMatch :: [Query]
1151 , boolQueryShouldMatch :: [Query]
1152 , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
1153 , boolQueryBoost :: Maybe Boost
1154 , boolQueryDisableCoord :: Maybe DisableCoord
1155 } deriving (Eq, Show, Typeable)
1157mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
1158mkBoolQuery must mustNot should =
1159 BoolQuery must mustNot should Nothing Nothing Nothing
1161data BoostingQuery =
1162 BoostingQuery { positiveQuery :: Query
1163 , negativeQuery :: Query
1164 , negativeBoost :: Boost } deriving (Eq, Show, Typeable)
1166data CommonTermsQuery =
1167 CommonTermsQuery { commonField :: FieldName
1168 , commonQuery :: QueryString
1169 , commonCutoffFrequency :: CutoffFrequency
1170 , commonLowFreqOperator :: BooleanOperator
1171 , commonHighFreqOperator :: BooleanOperator
1172 , commonMinimumShouldMatch :: Maybe CommonMinimumMatch
1173 , commonBoost :: Maybe Boost
1174 , commonAnalyzer :: Maybe Analyzer
1175 , commonDisableCoord :: Maybe DisableCoord
1176 } deriving (Eq, Show, Typeable)
1178data CommonMinimumMatch =
1179 CommonMinimumMatchHighLow MinimumMatchHighLow
1180 | CommonMinimumMatch MinimumMatch
1181 deriving (Eq, Show, Typeable)
1183data MinimumMatchHighLow =
1184 MinimumMatchHighLow { lowFreq :: MinimumMatch
1185 , highFreq :: MinimumMatch } deriving (Eq, Show, Typeable)
1187data Filter = AndFilter [Filter] Cache
1188 | OrFilter [Filter] Cache
1189 | NotFilter Filter Cache
1190 | IdentityFilter
1191 | BoolFilter BoolMatch
1192 | ExistsFilter FieldName -- always cached
1193 | GeoBoundingBoxFilter GeoBoundingBoxConstraint
1194 | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
1195 | GeoDistanceRangeFilter GeoPoint DistanceRange
1196 | GeoPolygonFilter FieldName [LatLon]
1197 | IdsFilter MappingName [DocId]
1198 | LimitFilter Int
1199 | MissingFilter FieldName Existence NullValue
1200 | PrefixFilter FieldName PrefixValue Cache
1201 | QueryFilter Query Cache
1202 | RangeFilter FieldName RangeValue RangeExecution Cache
1203 | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
1204 | TermFilter Term Cache
1205 deriving (Eq, Show, Typeable)
1207data ZeroTermsQuery = ZeroTermsNone
1208 | ZeroTermsAll deriving (Eq, Show, Typeable)
1210data RangeExecution = RangeExecutionIndex
1211 | RangeExecutionFielddata deriving (Eq, Show, Typeable)
1213newtype Regexp = Regexp Text deriving (Eq, Show, FromJSON)
1215data RegexpFlags = AllRegexpFlags
1216 | NoRegexpFlags
1217 | SomeRegexpFlags (NonEmpty RegexpFlag) deriving (Eq, Show)
1219data RegexpFlag = AnyString
1220 | Automaton
1221 | Complement
1222 | Empty
1223 | Intersection
1224 | Interval deriving (Eq, Show)
1226newtype LessThan = LessThan Double deriving (Eq, Show)
1227newtype LessThanEq = LessThanEq Double deriving (Eq, Show)
1228newtype GreaterThan = GreaterThan Double deriving (Eq, Show)
1229newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Show)
1231newtype LessThanD = LessThanD UTCTime deriving (Eq, Show)
1232newtype LessThanEqD = LessThanEqD UTCTime deriving (Eq, Show)
1233newtype GreaterThanD = GreaterThanD UTCTime deriving (Eq, Show)
1234newtype GreaterThanEqD = GreaterThanEqD UTCTime deriving (Eq, Show)
1236data RangeValue = RangeDateLte LessThanEqD
1237 | RangeDateLt LessThanD
1238 | RangeDateGte GreaterThanEqD
1239 | RangeDateGt GreaterThanD
1240 | RangeDateGtLt GreaterThanD LessThanD
1241 | RangeDateGteLte GreaterThanEqD LessThanEqD
1242 | RangeDateGteLt GreaterThanEqD LessThanD
1243 | RangeDateGtLte GreaterThanD LessThanEqD
1244 | RangeDoubleLte LessThanEq
1245 | RangeDoubleLt LessThan
1246 | RangeDoubleGte GreaterThanEq
1247 | RangeDoubleGt GreaterThan
1248 | RangeDoubleGtLt GreaterThan LessThan
1249 | RangeDoubleGteLte GreaterThanEq LessThanEq
1250 | RangeDoubleGteLt GreaterThanEq LessThan
1251 | RangeDoubleGtLte GreaterThan LessThanEq
1252 deriving (Eq, Show)
1254rangeValueToPair :: RangeValue -> [Pair]
1255rangeValueToPair rv = case rv of
1256 RangeDateLte (LessThanEqD t) -> ["lte" .= t]
1257 RangeDateGte (GreaterThanEqD t) -> ["gte" .= t]
1258 RangeDateLt (LessThanD t) -> ["lt" .= t]
1259 RangeDateGt (GreaterThanD t) -> ["gt" .= t]
1260 RangeDateGteLte (GreaterThanEqD l) (LessThanEqD g) -> ["gte" .= l, "lte" .= g]
1261 RangeDateGtLte (GreaterThanD l) (LessThanEqD g) -> ["gt" .= l, "lte" .= g]
1262 RangeDateGteLt (GreaterThanEqD l) (LessThanD g) -> ["gte" .= l, "lt" .= g]
1263 RangeDateGtLt (GreaterThanD l) (LessThanD g) -> ["gt" .= l, "lt" .= g]
1264 RangeDoubleLte (LessThanEq t) -> ["lte" .= t]
1265 RangeDoubleGte (GreaterThanEq t) -> ["gte" .= t]
1266 RangeDoubleLt (LessThan t) -> ["lt" .= t]
1267 RangeDoubleGt (GreaterThan t) -> ["gt" .= t]
1268 RangeDoubleGteLte (GreaterThanEq l) (LessThanEq g) -> ["gte" .= l, "lte" .= g]
1269 RangeDoubleGtLte (GreaterThan l) (LessThanEq g) -> ["gt" .= l, "lte" .= g]
1270 RangeDoubleGteLt (GreaterThanEq l) (LessThan g) -> ["gte" .= l, "lt" .= g]
1271 RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g]
1273data Term = Term { termField :: Text
1274 , termValue :: Text } deriving (Eq, Show, Typeable)
1276data BoolMatch = MustMatch Term Cache
1277 | MustNotMatch Term Cache
1278 | ShouldMatch [Term] Cache deriving (Eq, Show, Typeable)
1280-- "memory" or "indexed"
1281data GeoFilterType = GeoFilterMemory
1282 | GeoFilterIndexed deriving (Eq, Show, Typeable)
1284data LatLon = LatLon { lat :: Double
1285 , lon :: Double } deriving (Eq, Show, Typeable)
1287data GeoBoundingBox =
1288 GeoBoundingBox { topLeft :: LatLon
1289 , bottomRight :: LatLon } deriving (Eq, Show, Typeable)
1291data GeoBoundingBoxConstraint =
1292 GeoBoundingBoxConstraint { geoBBField :: FieldName
1293 , constraintBox :: GeoBoundingBox
1294 , bbConstraintcache :: Cache
1295 , geoType :: GeoFilterType
1296 } deriving (Eq, Show, Typeable)
1298data GeoPoint =
1299 GeoPoint { geoField :: FieldName
1300 , latLon :: LatLon} deriving (Eq, Show, Typeable)
1302data DistanceUnit = Miles
1303 | Yards
1304 | Feet
1305 | Inches
1306 | Kilometers
1307 | Meters
1308 | Centimeters
1309 | Millimeters
1310 | NauticalMiles deriving (Eq, Show, Typeable)
1312data DistanceType = Arc
1313 | SloppyArc -- doesn't exist <1.0
1314 | Plane deriving (Eq, Show, Typeable)
1316data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
1317 | NoOptimizeBbox deriving (Eq, Show, Typeable)
1319data Distance =
1320 Distance { coefficient :: Double
1321 , unit :: DistanceUnit } deriving (Eq, Show, Typeable)
1323data DistanceRange =
1324 DistanceRange { distanceFrom :: Distance
1325 , distanceTo :: Distance } deriving (Eq, Show)
1327data SearchResult a =
1328 SearchResult { took :: Int
1329 , timedOut :: Bool
1330 , shards :: ShardResult
1331 , searchHits :: SearchHits a
1332 , aggregations :: Maybe AggregationResults
1333 , scrollId :: Maybe ScrollId } deriving (Eq, Show)
1335newtype ScrollId = ScrollId Text deriving (Eq, Show, Ord, ToJSON, FromJSON)
1337type Score = Maybe Double
1339data SearchHits a =
1340 SearchHits { hitsTotal :: Int
1341 , maxScore :: Score
1342 , hits :: [Hit a] } deriving (Eq, Show)
1345instance Monoid (SearchHits a) where
1346 mempty = SearchHits 0 Nothing mempty
1347 mappend (SearchHits ta ma ha) (SearchHits tb mb hb) =
1348 SearchHits (ta + tb) (max ma mb) (ha <> hb)
1351data Hit a =
1352 Hit { hitIndex :: IndexName
1353 , hitType :: MappingName
1354 , hitDocId :: DocId
1355 , hitScore :: Score
1356 , hitSource :: Maybe a
1357 , hitHighlight :: Maybe HitHighlight } deriving (Eq, Show)
1359data ShardResult =
1360 ShardResult { shardTotal :: Int
1361 , shardsSuccessful :: Int
1362 , shardsFailed :: Int } deriving (Eq, Show, Generic)
1364type HitHighlight = M.Map Text [Text]
1366showText :: Show a => a -> Text
1367showText = T.pack . show
1369type Aggregations = M.Map Text Aggregation
1371emptyAggregations :: Aggregations
1372emptyAggregations = M.empty
1374mkAggregations :: Text -> Aggregation -> Aggregations
1375mkAggregations name aggregation = M.insert name aggregation emptyAggregations
1377data TermOrder = TermOrder{ termSortField :: Text
1378 , termSortOrder :: SortOrder } deriving (Eq, Show)
1380data TermInclusion = TermInclusion Text
1381 | TermPattern Text Text deriving (Eq, Show)
1383data CollectionMode = BreadthFirst
1384 | DepthFirst deriving (Eq, Show)
1386data ExecutionHint = Ordinals
1387 | GlobalOrdinals
1388 | GlobalOrdinalsHash
1389 | GlobalOrdinalsLowCardinality
1390 | Map deriving (Eq, Show)
1392data TimeInterval = Weeks
1393 | Days
1394 | Hours
1395 | Minutes
1396 | Seconds deriving (Eq)
1398data Interval = Year
1399 | Quarter
1400 | Month
1401 | Week
1402 | Day
1403 | Hour
1404 | Minute
1405 | Second
1406 | FractionalInterval Float TimeInterval deriving (Eq, Show)
1408data Aggregation = TermsAgg TermsAggregation
1409 | DateHistogramAgg DateHistogramAggregation
1410 | ValueCountAgg ValueCountAggregation
1411 | FilterAgg FilterAggregation deriving (Eq, Show)
1414data TermsAggregation = TermsAggregation { term :: Either Text Text
1415 , termInclude :: Maybe TermInclusion
1416 , termExclude :: Maybe TermInclusion
1417 , termOrder :: Maybe TermOrder
1418 , termMinDocCount :: Maybe Int
1419 , termSize :: Maybe Int
1420 , termShardSize :: Maybe Int
1421 , termCollectMode :: Maybe CollectionMode
1422 , termExecutionHint :: Maybe ExecutionHint
1423 , termAggs :: Maybe Aggregations
1424 } deriving (Eq, Show)
1426data DateHistogramAggregation = DateHistogramAggregation { dateField :: FieldName
1427 , dateInterval :: Interval
1428 , dateFormat :: Maybe Text
1429 -- pre and post deprecated in 1.5
1430 , datePreZone :: Maybe Text
1431 , datePostZone :: Maybe Text
1432 , datePreOffset :: Maybe Text
1433 , datePostOffset :: Maybe Text
1434 , dateAggs :: Maybe Aggregations
1435 } deriving (Eq, Show)
1437-- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-valuecount-aggregation.html> for more information.
1438data ValueCountAggregation = FieldValueCount FieldName
1439 | ScriptValueCount Script deriving (Eq, Show)
1441-- | 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.
1442data FilterAggregation = FilterAggregation { faFilter :: Filter
1443 , faAggs :: Maybe Aggregations} deriving (Eq, Show)
1445mkTermsAggregation :: Text -> TermsAggregation
1446mkTermsAggregation t = TermsAggregation (Left t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1448mkTermsScriptAggregation :: Text -> TermsAggregation
1449mkTermsScriptAggregation t = TermsAggregation (Right t) Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
1451mkDateHistogram :: FieldName -> Interval -> DateHistogramAggregation
1452mkDateHistogram t i = DateHistogramAggregation t i Nothing Nothing Nothing Nothing Nothing Nothing
1454instance ToJSON Version where
1455 toJSON Version {..} = object ["number" .= number
1456 ,"build_hash" .= build_hash
1457 ,"build_timestamp" .= build_timestamp
1458 ,"build_snapshot" .= build_snapshot
1459 ,"lucene_version" .= lucene_version]
1461instance FromJSON Version where
1462 parseJSON = withObject "Version" parse
1463 where parse o = Version
1464 <$> o .: "number"
1465 <*> o .: "build_hash"
1466 <*> o .: "build_timestamp"
1467 <*> o .: "build_snapshot"
1468 <*> o .: "lucene_version"
1470instance ToJSON TermOrder where
1471 toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
1473instance ToJSON TermInclusion where
1474 toJSON (TermInclusion x) = toJSON x
1475 toJSON (TermPattern pattern flags) = omitNulls [ "pattern" .= pattern,
1476 "flags" .= flags]
1478instance ToJSON CollectionMode where
1479 toJSON BreadthFirst = "breadth_first"
1480 toJSON DepthFirst = "depth_first"
1482instance ToJSON ExecutionHint where
1483 toJSON Ordinals = "ordinals"
1484 toJSON GlobalOrdinals = "global_ordinals"
1485 toJSON GlobalOrdinalsHash = "global_ordinals_hash"
1486 toJSON GlobalOrdinalsLowCardinality = "global_ordinals_low_cardinality"
1487 toJSON Map = "map"
1489instance ToJSON Interval where
1490 toJSON Year = "year"
1491 toJSON Quarter = "quarter"
1492 toJSON Month = "month"
1493 toJSON Week = "week"
1494 toJSON Day = "day"
1495 toJSON Hour = "hour"
1496 toJSON Minute = "minute"
1497 toJSON Second = "second"
1498 toJSON (FractionalInterval fraction interval) = toJSON $ show fraction ++ show interval
1500instance Show TimeInterval where
1501 show Weeks = "w"
1502 show Days = "d"
1503 show Hours = "h"
1504 show Minutes = "m"
1505 show Seconds = "s"
1507instance ToJSON Aggregation where
1508 toJSON (TermsAgg (TermsAggregation term include exclude order minDocCount size shardSize collectMode executionHint termAggs)) =
1509 omitNulls ["terms" .= omitNulls [ toJSON' term,
1510 "include" .= include,
1511 "exclude" .= exclude,
1512 "order" .= order,
1513 "min_doc_count" .= minDocCount,
1514 "size" .= size,
1515 "shard_size" .= shardSize,
1516 "collect_mode" .= collectMode,
1517 "execution_hint" .= executionHint
1518 ],
1519 "aggs" .= termAggs ]
1520 where
1521 toJSON' x = case x of { Left y -> "field" .= y; Right y -> "script" .= y }
1523 toJSON (DateHistogramAgg (DateHistogramAggregation field interval format preZone postZone preOffset postOffset dateHistoAggs)) =
1524 omitNulls ["date_histogram" .= omitNulls [ "field" .= field,
1525 "interval" .= interval,
1526 "format" .= format,
1527 "pre_zone" .= preZone,
1528 "post_zone" .= postZone,
1529 "pre_offset" .= preOffset,
1530 "post_offset" .= postOffset
1531 ],
1532 "aggs" .= dateHistoAggs ]
1533 toJSON (ValueCountAgg a) = object ["value_count" .= v]
1534 where v = case a of
1535 (FieldValueCount (FieldName n)) -> object ["field" .= n]
1536 (ScriptValueCount (Script s)) -> object ["script" .= s]
1537 toJSON (FilterAgg (FilterAggregation filt ags)) =
1538 omitNulls [ "filter" .= filt
1539 , "aggs" .= ags]
1541type AggregationResults = M.Map Text Value
1543class BucketAggregation a where
1544 key :: a -> Text
1545 docCount :: a -> Int
1546 aggs :: a -> Maybe AggregationResults
1549data Bucket a = Bucket { buckets :: [a]} deriving (Show)
1551data TermsResult = TermsResult { termKey :: Text
1552 , termsDocCount :: Int
1553 , termsAggs :: Maybe AggregationResults } deriving (Show)
1555data DateHistogramResult = DateHistogramResult { dateKey :: Int
1556 , dateKeyStr :: Maybe Text
1557 , dateDocCount :: Int
1558 , dateHistogramAggs :: Maybe AggregationResults } deriving (Show)
1560toTerms :: Text -> AggregationResults -> Maybe (Bucket TermsResult)
1561toTerms t a = M.lookup t a >>= deserialize
1562 where deserialize = parseMaybe parseJSON
1564toDateHistogram :: Text -> AggregationResults -> Maybe (Bucket DateHistogramResult)
1565toDateHistogram t a = M.lookup t a >>= deserialize
1566 where deserialize = parseMaybe parseJSON
1568instance BucketAggregation TermsResult where
1569 key = termKey
1570 docCount = termsDocCount
1571 aggs = termsAggs
1573instance BucketAggregation DateHistogramResult where
1574 key = showText . dateKey
1575 docCount = dateDocCount
1576 aggs = dateHistogramAggs
1578instance (FromJSON a, BucketAggregation a) => FromJSON (Bucket a) where
1579 parseJSON (Object v) = Bucket <$>
1580 v .: "buckets"
1581 parseJSON _ = mempty
1583instance FromJSON TermsResult where
1584 parseJSON (Object v) = TermsResult <$>
1585 v .: "key" <*>
1586 v .: "doc_count" <*>
1587 v .:? "aggregations"
1588 parseJSON _ = mempty
1590instance FromJSON DateHistogramResult where
1591 parseJSON (Object v) = DateHistogramResult <$>
1592 v .: "key" <*>
1593 v .:? "key_as_string" <*>
1594 v .: "doc_count" <*>
1595 v .:? "aggregations"
1596 parseJSON _ = mempty
1598instance Monoid Filter where
1599 mempty = IdentityFilter
1600 mappend a b = AndFilter [a, b] defaultCache
1602instance Seminearring Filter where
1603 a <||> b = OrFilter [a, b] defaultCache
1605instance ToJSON Filter where
1606 toJSON (AndFilter filters cache) =
1607 object ["and" .=
1608 object [ "filters" .= fmap toJSON filters
1609 , "_cache" .= cache]]
1611 toJSON (OrFilter filters cache) =
1612 object ["or" .=
1613 object [ "filters" .= fmap toJSON filters
1614 , "_cache" .= cache]]
1616 toJSON (NotFilter notFilter cache) =
1617 object ["not" .=
1618 object ["filter" .= notFilter
1619 , "_cache" .= cache]]
1621 toJSON (IdentityFilter) =
1622 object ["match_all" .= object []]
1624 toJSON (TermFilter (Term termFilterField termFilterValue) cache) =
1625 object ["term" .= object base]
1626 where base = [termFilterField .= termFilterValue,
1627 "_cache" .= cache]
1629 toJSON (ExistsFilter (FieldName fieldName)) =
1630 object ["exists" .= object
1631 ["field" .= fieldName]]
1633 toJSON (BoolFilter boolMatch) =
1634 object ["bool" .= boolMatch]
1636 toJSON (GeoBoundingBoxFilter bbConstraint) =
1637 object ["geo_bounding_box" .= bbConstraint]
1639 toJSON (GeoDistanceFilter (GeoPoint (FieldName distanceGeoField) geoDistLatLon)
1640 distance distanceType optimizeBbox cache) =
1641 object ["geo_distance" .=
1642 object ["distance" .= distance
1643 , "distance_type" .= distanceType
1644 , "optimize_bbox" .= optimizeBbox
1645 , distanceGeoField .= geoDistLatLon
1646 , "_cache" .= cache]]
1648 toJSON (GeoDistanceRangeFilter (GeoPoint (FieldName gddrField) drLatLon)
1649 (DistanceRange geoDistRangeDistFrom drDistanceTo)) =
1650 object ["geo_distance_range" .=
1651 object ["from" .= geoDistRangeDistFrom
1652 , "to" .= drDistanceTo
1653 , gddrField .= drLatLon]]
1655 toJSON (GeoPolygonFilter (FieldName geoPolygonFilterField) latLons) =
1656 object ["geo_polygon" .=
1657 object [geoPolygonFilterField .=
1658 object ["points" .= fmap toJSON latLons]]]
1660 toJSON (IdsFilter (MappingName mappingName) values) =
1661 object ["ids" .=
1662 object ["type" .= mappingName
1663 , "values" .= fmap unpackId values]]
1665 toJSON (LimitFilter limit) =
1666 object ["limit" .= object ["value" .= limit]]
1668 toJSON (MissingFilter (FieldName fieldName) (Existence existence) (NullValue nullValue)) =
1669 object ["missing" .=
1670 object ["field" .= fieldName
1671 , "existence" .= existence
1672 , "null_value" .= nullValue]]
1674 toJSON (PrefixFilter (FieldName fieldName) fieldValue cache) =
1675 object ["prefix" .=
1676 object [fieldName .= fieldValue
1677 , "_cache" .= cache]]
1679 toJSON (QueryFilter query False) =
1680 object ["query" .= toJSON query ]
1681 toJSON (QueryFilter query True) =
1682 object ["fquery" .=
1683 object [ "query" .= toJSON query
1684 , "_cache" .= True ]]
1686 toJSON (RangeFilter (FieldName fieldName) rangeValue rangeExecution cache) =
1687 object ["range" .=
1688 object [ fieldName .= object (rangeValueToPair rangeValue)
1689 , "execution" .= rangeExecution
1690 , "_cache" .= cache]]
1692 toJSON (RegexpFilter (FieldName fieldName)
1693 (Regexp regexText) flags (CacheName cacheName) cache (CacheKey cacheKey)) =
1694 object ["regexp" .=
1695 object [fieldName .=
1696 object ["value" .= regexText
1697 , "flags" .= flags]
1698 , "_name" .= cacheName
1699 , "_cache" .= cache
1700 , "_cache_key" .= cacheKey]]
1702instance FromJSON Filter where
1703 parseJSON = withObject "Filter" parse
1704 where parse o = andFilter `taggedWith` "and"
1705 <|> orFilter `taggedWith` "or"
1706 <|> notFilter `taggedWith` "not"
1707 <|> identityFilter `taggedWith` "match_all"
1708 <|> boolFilter `taggedWith` "bool"
1709 <|> existsFilter `taggedWith` "exists"
1710 <|> geoBoundingBoxFilter `taggedWith` "geo_bounding_box"
1711 <|> geoDistanceFilter `taggedWith` "geo_distance"
1712 <|> geoDistanceRangeFilter `taggedWith` "geo_distance_range"
1713 <|> geoPolygonFilter `taggedWith` "geo_polygon"
1714 <|> idsFilter `taggedWith` "ids"
1715 <|> limitFilter `taggedWith` "limit"
1716 <|> missingFilter `taggedWith` "missing"
1717 <|> prefixFilter `taggedWith` "prefix"
1718 <|> queryFilter `taggedWith` "query"
1719 <|> fqueryFilter `taggedWith` "fquery"
1720 <|> rangeFilter `taggedWith` "range"
1721 <|> regexpFilter `taggedWith` "regexp"
1722 <|> termFilter `taggedWith` "term"
1723 where taggedWith parser k = parser =<< o .: k
1724 andFilter o = AndFilter <$> o .: "filters"
1725 <*> o .:? "_cache" .!= defaultCache
1726 orFilter o = OrFilter <$> o .: "filters"
1727 <*> o .:? "_cache" .!= defaultCache
1728 notFilter o = NotFilter <$> o .: "filter"
1729 <*> o .: "_cache" .!= defaultCache
1730 identityFilter :: Object -> Parser Filter
1731 identityFilter m
1732 | HM.null m = pure IdentityFilter
1733 | otherwise = fail ("Identityfilter expected empty object but got " <> show m)
1734 boolFilter = pure . BoolFilter
1735 existsFilter o = ExistsFilter <$> o .: "field"
1736 geoBoundingBoxFilter = pure . GeoBoundingBoxFilter
1737 geoDistanceFilter o = do
1738 case HM.toList (deleteSeveral ["distance", "distance_type", "optimize_bbox", "_cache"] o) of
1739 [(fn, v)] -> do
1740 gp <- GeoPoint (FieldName fn) <$> parseJSON v
1741 GeoDistanceFilter gp <$> o .: "distance"
1742 <*> o .: "distance_type"
1743 <*> o .: "optimize_bbox"
1744 <*> o .:? "_cache" .!= defaultCache
1745 _ -> fail "Could not find GeoDistanceFilter field name"
1746 geoDistanceRangeFilter o = do
1747 case HM.toList (deleteSeveral ["from", "to"] o) of
1748 [(fn, v)] -> do
1749 gp <- GeoPoint (FieldName fn) <$> parseJSON v
1750 rng <- DistanceRange <$> o .: "from" <*> o .: "to"
1751 return (GeoDistanceRangeFilter gp rng)
1752 _ -> fail "Could not find GeoDistanceRangeFilter field name"
1753 geoPolygonFilter = fieldTagged $ \fn o -> GeoPolygonFilter fn <$> o .: "points"
1754 idsFilter o = IdsFilter <$> o .: "type"
1755 <*> o .: "values"
1756 limitFilter o = LimitFilter <$> o .: "value"
1757 missingFilter o = MissingFilter <$> o .: "field"
1758 <*> o .: "existence"
1759 <*> o .: "null_value"
1760 prefixFilter o = case HM.toList (HM.delete "_cache" o) of
1761 [(fn, String v)] -> PrefixFilter (FieldName fn) v <$> o .:? "_cache" .!= defaultCache
1762 _ -> fail "Could not parse PrefixFilter"
1764 queryFilter q = pure (QueryFilter q False)
1765 fqueryFilter o = QueryFilter <$> o .: "query" <*> pure True
1766 rangeFilter o = case HM.toList (deleteSeveral ["execution", "_cache"] o) of
1767 [(fn, v)] -> RangeFilter (FieldName fn)
1768 <$> parseJSON v
1769 <*> o .: "execution"
1770 <*> o .:? "_cache" .!= defaultCache
1771 _ -> fail "Could not find field name for RangeFilter"
1772 regexpFilter o = case HM.toList (deleteSeveral ["_name", "_cache", "_cache_key"] o) of
1773 [(fn, Object o')] -> RegexpFilter (FieldName fn)
1774 <$> o' .: "value"
1775 <*> o' .: "flags"
1776 <*> o .: "_name"
1777 <*> o .:? "_cache" .!= defaultCache
1778 <*> o .: "_cache_key"
1779 _ -> fail "Could not find field name for RegexpFilter"
1780 termFilter o = case HM.toList (HM.delete "_cache" o) of
1781 [(termField, String termVal)] -> TermFilter (Term termField termVal)
1782 <$> o .:? "_cache" .!= defaultCache
1783 _ -> fail "Could not find term field for TermFilter"
1785fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
1786fieldTagged f o = case HM.toList o of
1787 [(k, Object o')] -> f (FieldName k) o'
1788 _ -> fail "Expected object with 1 field-named key"
1790instance ToJSON GeoPoint where
1791 toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
1792 object [ geoPointField .= geoPointLatLon ]
1795instance ToJSON Query where
1796 toJSON (TermQuery (Term termQueryField termQueryValue) boost) =
1797 object [ "term" .=
1798 object [termQueryField .= object merged]]
1799 where
1800 base = [ "value" .= termQueryValue ]
1801 boosted = maybe [] (return . ("boost" .=)) boost
1802 merged = mappend base boosted
1804 toJSON (TermsQuery fieldName terms) =
1805 object [ "terms" .= object conjoined ]
1806 where conjoined = [fieldName .= terms]
1807 toJSON (IdsQuery idsQueryMappingName docIds) =
1808 object [ "ids" .= object conjoined ]
1809 where conjoined = [ "type" .= idsQueryMappingName
1810 , "values" .= fmap toJSON docIds ]
1812 toJSON (QueryQueryStringQuery qQueryStringQuery) =
1813 object [ "query_string" .= qQueryStringQuery ]
1815 toJSON (QueryMatchQuery matchQuery) =
1816 object [ "match" .= matchQuery ]
1818 toJSON (QueryMultiMatchQuery multiMatchQuery) =
1819 toJSON multiMatchQuery
1821 toJSON (QueryBoolQuery boolQuery) =
1822 object [ "bool" .= boolQuery ]
1824 toJSON (QueryBoostingQuery boostingQuery) =
1825 object [ "boosting" .= boostingQuery ]
1827 toJSON (QueryCommonTermsQuery commonTermsQuery) =
1828 object [ "common" .= commonTermsQuery ]
1830 toJSON (ConstantScoreFilter csFilter boost) =
1831 object ["constant_score" .= object ["filter" .= csFilter
1832 , "boost" .= boost]]
1834 toJSON (ConstantScoreQuery query boost) =
1835 object ["constant_score" .= object ["query" .= query
1836 , "boost" .= boost]]
1838 toJSON (QueryDisMaxQuery disMaxQuery) =
1839 object [ "dis_max" .= disMaxQuery ]
1841 toJSON (QueryFilteredQuery qFilteredQuery) =
1842 object [ "filtered" .= qFilteredQuery ]
1844 toJSON (QueryFuzzyLikeThisQuery fuzzyQuery) =
1845 object [ "fuzzy_like_this" .= fuzzyQuery ]
1847 toJSON (QueryFuzzyLikeFieldQuery fuzzyFieldQuery) =
1848 object [ "fuzzy_like_this_field" .= fuzzyFieldQuery ]
1850 toJSON (QueryFuzzyQuery fuzzyQuery) =
1851 object [ "fuzzy" .= fuzzyQuery ]
1853 toJSON (QueryHasChildQuery childQuery) =
1854 object [ "has_child" .= childQuery ]
1856 toJSON (QueryHasParentQuery parentQuery) =
1857 object [ "has_parent" .= parentQuery ]
1859 toJSON (QueryIndicesQuery qIndicesQuery) =
1860 object [ "indices" .= qIndicesQuery ]
1862 toJSON (MatchAllQuery boost) =
1863 object [ "match_all" .= omitNulls [ "boost" .= boost ] ]
1865 toJSON (QueryMoreLikeThisQuery query) =
1866 object [ "more_like_this" .= query ]
1868 toJSON (QueryMoreLikeThisFieldQuery query) =
1869 object [ "more_like_this_field" .= query ]
1871 toJSON (QueryNestedQuery query) =
1872 object [ "nested" .= query ]
1874 toJSON (QueryPrefixQuery query) =
1875 object [ "prefix" .= query ]
1877 toJSON (QueryRangeQuery query) =
1878 object [ "range" .= query ]
1880 toJSON (QueryRegexpQuery query) =
1881 object [ "regexp" .= query ]
1883 toJSON (QuerySimpleQueryStringQuery query) =
1884 object [ "simple_query_string" .= query ]
1886instance FromJSON Query where
1887 parseJSON v = withObject "Query" parse v
1888 where parse o = termQuery `taggedWith` "term"
1889 <|> termsQuery `taggedWith` "terms"
1890 <|> idsQuery `taggedWith` "ids"
1891 <|> queryQueryStringQuery `taggedWith` "query_string"
1892 <|> queryMatchQuery `taggedWith` "match"
1893 <|> queryMultiMatchQuery --TODO: is this a precedence issue?
1894 <|> queryBoolQuery `taggedWith` "bool"
1895 <|> queryBoostingQuery `taggedWith` "boosting"
1896 <|> queryCommonTermsQuery `taggedWith` "common"
1897 <|> constantScoreFilter `taggedWith` "constant_score"
1898 <|> constantScoreQuery `taggedWith` "constant_score"
1899 <|> queryDisMaxQuery `taggedWith` "dis_max"
1900 <|> queryFilteredQuery `taggedWith` "filtered"
1901 <|> queryFuzzyLikeThisQuery `taggedWith` "fuzzy_like_this"
1902 <|> queryFuzzyLikeFieldQuery `taggedWith` "fuzzy_like_this_field"
1903 <|> queryFuzzyQuery `taggedWith` "fuzzy"
1904 <|> queryHasChildQuery `taggedWith` "has_child"
1905 <|> queryHasParentQuery `taggedWith` "has_parent"
1906 <|> queryIndicesQuery `taggedWith` "indices"
1907 <|> matchAllQuery `taggedWith` "match_all"
1908 <|> queryMoreLikeThisQuery `taggedWith` "more_like_this"
1909 <|> queryMoreLikeThisFieldQuery `taggedWith` "more_like_this_field"
1910 <|> queryNestedQuery `taggedWith` "nested"
1911 <|> queryPrefixQuery `taggedWith` "prefix"
1912 <|> queryRangeQuery `taggedWith` "range"
1913 <|> queryRegexpQuery `taggedWith` "regexp"
1914 <|> querySimpleQueryStringQuery `taggedWith` "simple_query_string"
1915 where taggedWith parser k = parser =<< o .: k
1916 termQuery = fieldTagged $ \(FieldName fn) o ->
1917 TermQuery <$> (Term fn <$> o .: "value") <*> o .:? "boost"
1918 termsQuery o = case HM.toList o of
1919 [(fn, vs)] -> do vals <- parseJSON vs
1920 case vals of
1921 x:xs -> return (TermsQuery fn (x :| xs))
1922 _ -> fail "Expected non empty list of values"
1923 _ -> fail "Expected object with 1 field-named key"
1924 idsQuery o = IdsQuery <$> o .: "type"
1925 <*> o .: "values"
1926 queryQueryStringQuery = pure . QueryQueryStringQuery
1927 queryMatchQuery = pure . QueryMatchQuery
1928 queryMultiMatchQuery = QueryMultiMatchQuery <$> parseJSON v
1929 queryBoolQuery = pure . QueryBoolQuery
1930 queryBoostingQuery = pure . QueryBoostingQuery
1931 queryCommonTermsQuery = pure . QueryCommonTermsQuery
1932 constantScoreFilter o = case HM.lookup "filter" o of
1933 Just x -> ConstantScoreFilter <$> parseJSON x
1934 <*> o .: "boost"
1935 _ -> fail "Does not appear to be a ConstantScoreFilter"
1936 constantScoreQuery o = case HM.lookup "query" o of
1937 Just x -> ConstantScoreQuery <$> parseJSON x
1938 <*> o .: "boost"
1939 _ -> fail "Does not appear to be a ConstantScoreQuery"
1940 queryDisMaxQuery = pure . QueryDisMaxQuery
1941 queryFilteredQuery = pure . QueryFilteredQuery
1942 queryFuzzyLikeThisQuery = pure . QueryFuzzyLikeThisQuery
1943 queryFuzzyLikeFieldQuery = pure . QueryFuzzyLikeFieldQuery
1944 queryFuzzyQuery = pure . QueryFuzzyQuery
1945 queryHasChildQuery = pure . QueryHasChildQuery
1946 queryHasParentQuery = pure . QueryHasParentQuery
1947 queryIndicesQuery = pure . QueryIndicesQuery
1948 matchAllQuery o = MatchAllQuery <$> o .:? "boost"
1949 queryMoreLikeThisQuery = pure . QueryMoreLikeThisQuery
1950 queryMoreLikeThisFieldQuery = pure . QueryMoreLikeThisFieldQuery
1951 queryNestedQuery = pure . QueryNestedQuery
1952 queryPrefixQuery = pure . QueryPrefixQuery
1953 queryRangeQuery = pure . QueryRangeQuery
1954 queryRegexpQuery = pure . QueryRegexpQuery
1955 querySimpleQueryStringQuery = pure . QuerySimpleQueryStringQuery
1958omitNulls :: [(Text, Value)] -> Value
1959omitNulls = object . filter notNull where
1960 notNull (_, Null) = False
1961 notNull (_, Array a) = (not . V.null) a
1962 notNull _ = True
1965instance ToJSON SimpleQueryStringQuery where
1966 toJSON SimpleQueryStringQuery {..} =
1967 omitNulls (base ++ maybeAdd)
1968 where base = [ "query" .= simpleQueryStringQuery ]
1969 maybeAdd = [ "fields" .= simpleQueryStringField
1970 , "default_operator" .= simpleQueryStringOperator
1971 , "analyzer" .= simpleQueryStringAnalyzer
1972 , "flags" .= simpleQueryStringFlags
1973 , "lowercase_expanded_terms" .= simpleQueryStringLowercaseExpanded
1974 , "locale" .= simpleQueryStringLocale ]
1976instance FromJSON SimpleQueryStringQuery where
1977 parseJSON = withObject "SimpleQueryStringQuery" parse
1978 where parse o = SimpleQueryStringQuery <$> o .: "query"
1979 <*> o .:? "fields"
1980 <*> o .:? "default_operator"
1981 <*> o .:? "analyzer"
1982 <*> (parseFlags <$> o .:? "flags")
1983 <*> o .:? "lowercase_expanded_terms"
1984 <*> o .:? "locale"
1985 parseFlags (Just (x:xs)) = Just (x :| xs)
1986 parseFlags _ = Nothing
1988instance ToJSON FieldOrFields where
1989 toJSON (FofField fieldName) =
1990 toJSON fieldName
1991 toJSON (FofFields fieldNames) =
1992 toJSON fieldNames
1994instance FromJSON FieldOrFields where
1995 parseJSON v = FofField <$> parseJSON v
1996 <|> FofFields <$> (parseNEJSON =<< parseJSON v)
1998instance ToJSON SimpleQueryFlag where
1999 toJSON SimpleQueryAll = "ALL"
2000 toJSON SimpleQueryNone = "NONE"
2001 toJSON SimpleQueryAnd = "AND"
2002 toJSON SimpleQueryOr = "OR"
2003 toJSON SimpleQueryPrefix = "PREFIX"
2004 toJSON SimpleQueryPhrase = "PHRASE"
2005 toJSON SimpleQueryPrecedence = "PRECEDENCE"
2006 toJSON SimpleQueryEscape = "ESCAPE"
2007 toJSON SimpleQueryWhitespace = "WHITESPACE"
2008 toJSON SimpleQueryFuzzy = "FUZZY"
2009 toJSON SimpleQueryNear = "NEAR"
2010 toJSON SimpleQuerySlop = "SLOP"
2012instance FromJSON SimpleQueryFlag where
2013 parseJSON = withText "SimpleQueryFlag" parse
2014 where parse "ALL" = pure SimpleQueryAll
2015 parse "NONE" = pure SimpleQueryNone
2016 parse "AND" = pure SimpleQueryAnd
2017 parse "OR" = pure SimpleQueryOr
2018 parse "PREFIX" = pure SimpleQueryPrefix
2019 parse "PHRASE" = pure SimpleQueryPhrase
2020 parse "PRECEDENCE" = pure SimpleQueryPrecedence
2021 parse "ESCAPE" = pure SimpleQueryEscape
2022 parse "WHITESPACE" = pure SimpleQueryWhitespace
2023 parse "FUZZY" = pure SimpleQueryFuzzy
2024 parse "NEAR" = pure SimpleQueryNear
2025 parse "SLOP" = pure SimpleQuerySlop
2026 parse f = fail ("Unexpected SimpleQueryFlag: " <> show f)
2028instance ToJSON RegexpQuery where
2029 toJSON (RegexpQuery (FieldName rqQueryField)
2030 (Regexp regexpQueryQuery) rqQueryFlags
2031 rqQueryBoost) =
2032 object [ rqQueryField .= omitNulls base ]
2033 where base = [ "value" .= regexpQueryQuery
2034 , "flags" .= rqQueryFlags
2035 , "boost" .= rqQueryBoost ]
2037instance FromJSON RegexpQuery where
2038 parseJSON = withObject "RegexpQuery" parse
2039 where parse = fieldTagged $ \fn o ->
2040 RegexpQuery fn
2041 <$> o .: "value"
2042 <*> o .: "flags"
2043 <*> o .:? "boost"
2045instance ToJSON QueryStringQuery where
2046 toJSON (QueryStringQuery qsQueryString
2047 qsDefaultField qsOperator
2048 qsAnalyzer qsAllowWildcard
2049 qsLowercaseExpanded qsEnablePositionIncrements
2050 qsFuzzyMaxExpansions qsFuzziness
2051 qsFuzzyPrefixLength qsPhraseSlop
2052 qsBoost qsAnalyzeWildcard
2053 qsGeneratePhraseQueries qsMinimumShouldMatch
2054 qsLenient qsLocale) =
2055 omitNulls base
2056 where
2057 base = [ "query" .= qsQueryString
2058 , "default_field" .= qsDefaultField
2059 , "default_operator" .= qsOperator
2060 , "analyzer" .= qsAnalyzer
2061 , "allow_leading_wildcard" .= qsAllowWildcard
2062 , "lowercase_expanded_terms" .= qsLowercaseExpanded
2063 , "enable_position_increments" .= qsEnablePositionIncrements
2064 , "fuzzy_max_expansions" .= qsFuzzyMaxExpansions
2065 , "fuzziness" .= qsFuzziness
2066 , "fuzzy_prefix_length" .= qsFuzzyPrefixLength
2067 , "phrase_slop" .= qsPhraseSlop
2068 , "boost" .= qsBoost
2069 , "analyze_wildcard" .= qsAnalyzeWildcard
2070 , "auto_generate_phrase_queries" .= qsGeneratePhraseQueries
2071 , "minimum_should_match" .= qsMinimumShouldMatch
2072 , "lenient" .= qsLenient
2073 , "locale" .= qsLocale ]
2075instance FromJSON QueryStringQuery where
2076 parseJSON = withObject "QueryStringQuery" parse
2077 where parse o = QueryStringQuery
2078 <$> o .: "query"
2079 <*> o .:? "default_field"
2080 <*> o .:? "default_operator"
2081 <*> o .:? "analyzer"
2082 <*> o .:? "allow_leading_wildcard"
2083 <*> o .:? "lowercase_expanded_terms"
2084 <*> o .:? "enable_position_increments"
2085 <*> o .:? "fuzzy_max_expansions"
2086 <*> o .:? "fuzziness"
2087 <*> o .:? "fuzzy_prefix_length"
2088 <*> o .:? "phrase_slop"
2089 <*> o .:? "boost"
2090 <*> o .:? "analyze_wildcard"
2091 <*> o .:? "auto_generate_phrase_queries"
2092 <*> o .:? "minimum_should_match"
2093 <*> o .:? "lenient"
2094 <*> o .:? "locale"
2096instance ToJSON RangeQuery where
2097 toJSON (RangeQuery (FieldName fieldName) range boost) =
2098 object [ fieldName .= object conjoined ]
2099 where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
2101instance FromJSON RangeQuery where
2102 parseJSON = withObject "RangeQuery" parse
2103 where parse = fieldTagged $ \fn o ->
2104 RangeQuery fn
2105 <$> parseJSON (Object o)
2106 <*> o .: "boost"
2108instance FromJSON RangeValue where
2109 parseJSON = withObject "RangeValue" parse
2110 where parse o = parseDate o
2111 <|> parseDouble o
2112 parseDate o = do lt <- o .:? "lt"
2113 lte <- o .:? "lte"
2114 gt <- o .:? "gt"
2115 gte <- o .:? "gte"
2116 case (lt, lte, gt, gte) of
2117 (Just a, _, Just b, _) -> return (RangeDateGtLt (GreaterThanD b) (LessThanD a))
2118 (Just a, _, _, Just b)-> return (RangeDateGteLt (GreaterThanEqD b) (LessThanD a))
2119 (_, Just a, Just b, _)-> return (RangeDateGtLte (GreaterThanD b) (LessThanEqD a))
2120 (_, Just a, _, Just b)-> return (RangeDateGteLte (GreaterThanEqD b) (LessThanEqD a))
2121 (_, _, Just a, _)-> return (RangeDateGt (GreaterThanD a))
2122 (Just a, _, _, _)-> return (RangeDateLt (LessThanD a))
2123 (_, _, _, Just a)-> return (RangeDateGte (GreaterThanEqD a))
2124 (_, Just a, _, _)-> return (RangeDateLte (LessThanEqD a))
2125 (Nothing, Nothing, Nothing, Nothing) -> mzero
2126 parseDouble o = do lt <- o .:? "lt"
2127 lte <- o .:? "lte"
2128 gt <- o .:? "gt"
2129 gte <- o .:? "gte"
2130 case (lt, lte, gt, gte) of
2131 (Just a, _, Just b, _) -> return (RangeDoubleGtLt (GreaterThan b) (LessThan a))
2132 (Just a, _, _, Just b)-> return (RangeDoubleGteLt (GreaterThanEq b) (LessThan a))
2133 (_, Just a, Just b, _)-> return (RangeDoubleGtLte (GreaterThan b) (LessThanEq a))
2134 (_, Just a, _, Just b)-> return (RangeDoubleGteLte (GreaterThanEq b) (LessThanEq a))
2135 (_, _, Just a, _)-> return (RangeDoubleGt (GreaterThan a))
2136 (Just a, _, _, _)-> return (RangeDoubleLt (LessThan a))
2137 (_, _, _, Just a)-> return (RangeDoubleGte (GreaterThanEq a))
2138 (_, Just a, _, _)-> return (RangeDoubleLte (LessThanEq a))
2139 (Nothing, Nothing, Nothing, Nothing) -> mzero
2141instance ToJSON PrefixQuery where
2142 toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
2143 object [ fieldName .= omitNulls base ]
2144 where base = [ "value" .= queryValue
2145 , "boost" .= boost ]
2147instance FromJSON PrefixQuery where
2148 parseJSON = withObject "PrefixQuery" parse
2149 where parse = fieldTagged $ \fn o ->
2150 PrefixQuery fn
2151 <$> o .: "value"
2152 <*> o .:? "boost"
2154instance ToJSON NestedQuery where
2155 toJSON (NestedQuery nqPath nqScoreType nqQuery) =
2156 object [ "path" .= nqPath
2157 , "score_mode" .= nqScoreType
2158 , "query" .= nqQuery ]
2160instance FromJSON NestedQuery where
2161 parseJSON = withObject "NestedQuery" parse
2162 where parse o = NestedQuery
2163 <$> o .: "path"
2164 <*> o .: "score_mode"
2165 <*> o .: "query"
2167instance ToJSON MoreLikeThisFieldQuery where
2168 toJSON (MoreLikeThisFieldQuery text (FieldName fieldName)
2169 percent mtf mqt stopwords mindf maxdf
2170 minwl maxwl boostTerms boost analyzer) =
2171 object [ fieldName .= omitNulls base ]
2172 where base = [ "like_text" .= text
2173 , "percent_terms_to_match" .= percent
2174 , "min_term_freq" .= mtf
2175 , "max_query_terms" .= mqt
2176 , "stop_words" .= stopwords
2177 , "min_doc_freq" .= mindf
2178 , "max_doc_freq" .= maxdf
2179 , "min_word_length" .= minwl
2180 , "max_word_length" .= maxwl
2181 , "boost_terms" .= boostTerms
2182 , "boost" .= boost
2183 , "analyzer" .= analyzer ]
2185instance FromJSON MoreLikeThisFieldQuery where
2186 parseJSON = withObject "MoreLikeThisFieldQuery" parse
2187 where parse = fieldTagged $ \fn o ->
2188 MoreLikeThisFieldQuery
2189 <$> o .: "like_text"
2190 <*> pure fn
2191 <*> o .:? "percent_terms_to_match"
2192 <*> o .:? "min_term_freq"
2193 <*> o .:? "max_query_terms"
2194 <*> (optionalNE =<< o .:? "stop_words")
2195 <*> o .:? "min_doc_freq"
2196 <*> o .:? "max_doc_freq"
2197 <*> o .:? "min_word_length"
2198 <*> o .:? "max_word_length"
2199 <*> o .:? "boost_terms"
2200 <*> o .:? "boost"
2201 <*> o .:? "analyzer"
2202 optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2204instance ToJSON MoreLikeThisQuery where
2205 toJSON (MoreLikeThisQuery text fields percent
2206 mtf mqt stopwords mindf maxdf
2207 minwl maxwl boostTerms boost analyzer) =
2208 omitNulls base
2209 where base = [ "like_text" .= text
2210 , "fields" .= fields
2211 , "percent_terms_to_match" .= percent
2212 , "min_term_freq" .= mtf
2213 , "max_query_terms" .= mqt
2214 , "stop_words" .= stopwords
2215 , "min_doc_freq" .= mindf
2216 , "max_doc_freq" .= maxdf
2217 , "min_word_length" .= minwl
2218 , "max_word_length" .= maxwl
2219 , "boost_terms" .= boostTerms
2220 , "boost" .= boost
2221 , "analyzer" .= analyzer ]
2223instance FromJSON MoreLikeThisQuery where
2224 parseJSON = withObject "MoreLikeThisQuery" parse
2225 where parse o = MoreLikeThisQuery
2226 <$> o .: "like_text"
2227 <*> (optionalNE =<< o .:? "fields")
2228 <*> o .:? "percent_terms_to_match"
2229 <*> o .:? "min_term_freq"
2230 <*> o .:? "max_query_terms"
2231 <*> (optionalNE =<< o .:? "stop_words")
2232 <*> o .:? "min_doc_freq"
2233 <*> o .:? "max_doc_freq"
2234 <*> o .:? "min_word_length"
2235 <*> o .:? "max_word_length"
2236 <*> o .:? "boost_terms"
2237 <*> o .:? "boost"
2238 <*> o .:? "analyzer"
2239 optionalNE = maybe (pure Nothing) (fmap Just . parseNEJSON)
2241instance ToJSON IndicesQuery where
2242 toJSON (IndicesQuery indices query noMatch) =
2243 omitNulls [ "indices" .= indices
2244 , "no_match_query" .= noMatch
2245 , "query" .= query ]
2247instance FromJSON IndicesQuery where
2248 parseJSON = withObject "IndicesQuery" parse
2249 where parse o = IndicesQuery
2250 <$> o .:? "indices" .!= []
2251 <*> o .: "query"
2252 <*> o .:? "no_match_query"
2254instance ToJSON HasParentQuery where
2255 toJSON (HasParentQuery queryType query scoreType) =
2256 omitNulls [ "parent_type" .= queryType
2257 , "score_type" .= scoreType
2258 , "query" .= query ]
2260instance FromJSON HasParentQuery where
2261 parseJSON = withObject "HasParentQuery" parse
2262 where parse o = HasParentQuery
2263 <$> o .: "parent_type"
2264 <*> o .: "query"
2265 <*> o .:? "score_type"
2267instance ToJSON HasChildQuery where
2268 toJSON (HasChildQuery queryType query scoreType) =
2269 omitNulls [ "query" .= query
2270 , "score_type" .= scoreType
2271 , "type" .= queryType ]
2273instance FromJSON HasChildQuery where
2274 parseJSON = withObject "HasChildQuery" parse
2275 where parse o = HasChildQuery
2276 <$> o .: "type"
2277 <*> o .: "query"
2278 <*> o .:? "score_type"
2280instance ToJSON FuzzyQuery where
2281 toJSON (FuzzyQuery (FieldName fieldName) queryText
2282 prefixLength maxEx fuzziness boost) =
2283 object [ fieldName .= omitNulls base ]
2284 where base = [ "value" .= queryText
2285 , "fuzziness" .= fuzziness
2286 , "prefix_length" .= prefixLength
2287 , "boost" .= boost
2288 , "max_expansions" .= maxEx ]
2290instance FromJSON FuzzyQuery where
2291 parseJSON = withObject "FuzzyQuery" parse
2292 where parse = fieldTagged $ \fn o ->
2293 FuzzyQuery fn
2294 <$> o .: "value"
2295 <*> o .: "prefix_length"
2296 <*> o .: "max_expansions"
2297 <*> o .: "fuzziness"
2298 <*> o .:? "boost"
2300instance ToJSON FuzzyLikeFieldQuery where
2301 toJSON (FuzzyLikeFieldQuery (FieldName fieldName)
2302 fieldText maxTerms ignoreFreq fuzziness prefixLength
2303 boost analyzer) =
2304 object [ fieldName .=
2305 omitNulls [ "like_text" .= fieldText
2306 , "max_query_terms" .= maxTerms
2307 , "ignore_tf" .= ignoreFreq
2308 , "fuzziness" .= fuzziness
2309 , "prefix_length" .= prefixLength
2310 , "analyzer" .= analyzer
2311 , "boost" .= boost ]]
2313instance FromJSON FuzzyLikeFieldQuery where
2314 parseJSON = withObject "FuzzyLikeFieldQuery" parse
2315 where parse = fieldTagged $ \fn o ->
2316 FuzzyLikeFieldQuery fn
2317 <$> o .: "like_text"
2318 <*> o .: "max_query_terms"
2319 <*> o .: "ignore_tf"
2320 <*> o .: "fuzziness"
2321 <*> o .: "prefix_length"
2322 <*> o .: "boost"
2323 <*> o .:? "analyzer"
2325instance ToJSON FuzzyLikeThisQuery where
2326 toJSON (FuzzyLikeThisQuery fields text maxTerms
2327 ignoreFreq fuzziness prefixLength boost analyzer) =
2328 omitNulls base
2329 where base = [ "fields" .= fields
2330 , "like_text" .= text
2331 , "max_query_terms" .= maxTerms
2332 , "ignore_tf" .= ignoreFreq
2333 , "fuzziness" .= fuzziness
2334 , "prefix_length" .= prefixLength
2335 , "analyzer" .= analyzer
2336 , "boost" .= boost ]
2338instance FromJSON FuzzyLikeThisQuery where
2339 parseJSON = withObject "FuzzyLikeThisQuery" parse
2340 where parse o = FuzzyLikeThisQuery
2341 <$> o .:? "fields" .!= []
2342 <*> o .: "like_text"
2343 <*> o .: "max_query_terms"
2344 <*> o .: "ignore_tf"
2345 <*> o .: "fuzziness"
2346 <*> o .: "prefix_length"
2347 <*> o .: "boost"
2348 <*> o .:? "analyzer"
2350instance ToJSON FilteredQuery where
2351 toJSON (FilteredQuery query fFilter) =
2352 object [ "query" .= query
2353 , "filter" .= fFilter ]
2355instance FromJSON FilteredQuery where
2356 parseJSON = withObject "FilteredQuery" parse
2357 where parse o = FilteredQuery
2358 <$> o .: "query"
2359 <*> o .: "filter"
2361instance ToJSON DisMaxQuery where
2362 toJSON (DisMaxQuery queries tiebreaker boost) =
2363 omitNulls base
2364 where base = [ "queries" .= queries
2365 , "boost" .= boost
2366 , "tie_breaker" .= tiebreaker ]
2368instance FromJSON DisMaxQuery where
2369 parseJSON = withObject "DisMaxQuery" parse
2370 where parse o = DisMaxQuery
2371 <$> o .:? "queries" .!= []
2372 <*> o .: "tie_breaker"
2373 <*> o .:? "boost"
2375instance ToJSON CommonTermsQuery where
2376 toJSON (CommonTermsQuery (FieldName fieldName)
2377 (QueryString query) cf lfo hfo msm
2378 boost analyzer disableCoord) =
2379 object [fieldName .= omitNulls base ]
2380 where base = [ "query" .= query
2381 , "cutoff_frequency" .= cf
2382 , "low_freq_operator" .= lfo
2383 , "minimum_should_match" .= msm
2384 , "boost" .= boost
2385 , "analyzer" .= analyzer
2386 , "disable_coord" .= disableCoord
2387 , "high_freq_operator" .= hfo ]
2389instance FromJSON CommonTermsQuery where
2390 parseJSON = withObject "CommonTermsQuery" parse
2391 where parse = fieldTagged $ \fn o ->
2392 CommonTermsQuery fn
2393 <$> o .: "query"
2394 <*> o .: "cutoff_frequency"
2395 <*> o .: "low_freq_operator"
2396 <*> o .: "high_freq_operator"
2397 <*> o .:? "minimum_should_match"
2398 <*> o .:? "boost"
2399 <*> o .:? "analyzer"
2400 <*> o .:? "disable_coord"
2402instance ToJSON CommonMinimumMatch where
2403 toJSON (CommonMinimumMatch mm) = toJSON mm
2404 toJSON (CommonMinimumMatchHighLow (MinimumMatchHighLow lowF highF)) =
2405 object [ "low_freq" .= lowF
2406 , "high_freq" .= highF ]
2408instance FromJSON CommonMinimumMatch where
2409 parseJSON v = parseMinimum v
2410 <|> parseMinimumHighLow v
2411 where parseMinimum = fmap CommonMinimumMatch . parseJSON
2412 parseMinimumHighLow = fmap CommonMinimumMatchHighLow . withObject "CommonMinimumMatchHighLow" (\o ->
2413 MinimumMatchHighLow
2414 <$> o .: "low_freq"
2415 <*> o .: "high_freq")
2418instance ToJSON BoostingQuery where
2419 toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
2420 object [ "positive" .= bqPositiveQuery
2421 , "negative" .= bqNegativeQuery
2422 , "negative_boost" .= bqNegativeBoost ]
2424instance FromJSON BoostingQuery where
2425 parseJSON = withObject "BoostingQuery" parse
2426 where parse o = BoostingQuery
2427 <$> o .: "positive"
2428 <*> o .: "negative"
2429 <*> o .: "negative_boost"
2431instance ToJSON BoolQuery where
2432 toJSON (BoolQuery mustM notM shouldM bqMin boost disableCoord) =
2433 omitNulls base
2434 where base = [ "must" .= mustM
2435 , "must_not" .= notM
2436 , "should" .= shouldM
2437 , "minimum_should_match" .= bqMin
2438 , "boost" .= boost
2439 , "disable_coord" .= disableCoord ]
2441instance FromJSON BoolQuery where
2442 parseJSON = withObject "BoolQuery" parse
2443 where parse o = BoolQuery
2444 <$> o .:? "must" .!= []
2445 <*> o .:? "must_not" .!= []
2446 <*> o .:? "should" .!= []
2447 <*> o .:? "minimum_should_match"
2448 <*> o .:? "boost"
2449 <*> o .:? "disable_coord"
2451instance ToJSON MatchQuery where
2452 toJSON (MatchQuery (FieldName fieldName)
2453 (QueryString mqQueryString) booleanOperator
2454 zeroTermsQuery cutoffFrequency matchQueryType
2455 analyzer maxExpansions lenient boost) =
2456 object [ fieldName .= omitNulls base ]
2457 where base = [ "query" .= mqQueryString
2458 , "operator" .= booleanOperator
2459 , "zero_terms_query" .= zeroTermsQuery
2460 , "cutoff_frequency" .= cutoffFrequency
2461 , "type" .= matchQueryType
2462 , "analyzer" .= analyzer
2463 , "max_expansions" .= maxExpansions
2464 , "lenient" .= lenient
2465 , "boost" .= boost ]
2467instance FromJSON MatchQuery where
2468 parseJSON = withObject "MatchQuery" parse
2469 where parse = fieldTagged $ \fn o ->
2470 MatchQuery fn
2471 <$> o .: "query"
2472 <*> o .: "operator"
2473 <*> o .: "zero_terms_query"
2474 <*> o .:? "cutoff_frequency"
2475 <*> o .:? "type"
2476 <*> o .:? "analyzer"
2477 <*> o .:? "max_expansions"
2478 <*> o .:? "lenient"
2479 <*> o .:? "boost"
2481instance ToJSON MultiMatchQuery where
2482 toJSON (MultiMatchQuery fields (QueryString query) boolOp
2483 ztQ tb mmqt cf analyzer maxEx lenient) =
2484 object ["multi_match" .= omitNulls base]
2485 where base = [ "fields" .= fmap toJSON fields
2486 , "query" .= query
2487 , "operator" .= boolOp
2488 , "zero_terms_query" .= ztQ
2489 , "tiebreaker" .= tb
2490 , "type" .= mmqt
2491 , "cutoff_frequency" .= cf
2492 , "analyzer" .= analyzer
2493 , "max_expansions" .= maxEx
2494 , "lenient" .= lenient ]
2496instance FromJSON MultiMatchQuery where
2497 parseJSON = withObject "MultiMatchQuery" parse
2498 where parse raw = do o <- raw .: "multi_match"
2499 MultiMatchQuery
2500 <$> o .:? "fields" .!= []
2501 <*> o .: "query"
2502 <*> o .: "operator"
2503 <*> o .: "zero_terms_query"
2504 <*> o .:? "tiebreaker"
2505 <*> o .:? "type"
2506 <*> o .:? "cutoff_frequency"
2507 <*> o .:? "analyzer"
2508 <*> o .:? "max_expansions"
2509 <*> o .:? "lenient"
2511instance ToJSON MultiMatchQueryType where
2512 toJSON MultiMatchBestFields = "best_fields"
2513 toJSON MultiMatchMostFields = "most_fields"
2514 toJSON MultiMatchCrossFields = "cross_fields"
2515 toJSON MultiMatchPhrase = "phrase"
2516 toJSON MultiMatchPhrasePrefix = "phrase_prefix"
2518instance FromJSON MultiMatchQueryType where
2519 parseJSON = withText "MultiMatchPhrasePrefix" parse
2520 where parse "best_fields" = pure MultiMatchBestFields
2521 parse "most_fields" = pure MultiMatchMostFields
2522 parse "cross_fields" = pure MultiMatchCrossFields
2523 parse "phrase" = pure MultiMatchPhrase
2524 parse "phrase_prefix" = pure MultiMatchPhrasePrefix
2525 parse t = fail ("Unexpected MultiMatchPhrasePrefix: " <> show t)
2527instance ToJSON BooleanOperator where
2528 toJSON And = String "and"
2529 toJSON Or = String "or"
2531instance FromJSON BooleanOperator where
2532 parseJSON = withText "BooleanOperator" parse
2533 where parse "and" = pure And
2534 parse "or" = pure Or
2535 parse o = fail ("Unexpected BooleanOperator: " <> show o)
2537instance ToJSON ZeroTermsQuery where
2538 toJSON ZeroTermsNone = String "none"
2539 toJSON ZeroTermsAll = String "all"
2541instance FromJSON ZeroTermsQuery where
2542 parseJSON = withText "ZeroTermsQuery" parse
2543 where parse "none" = pure ZeroTermsNone
2544 parse "all" = pure ZeroTermsAll
2545 parse q = fail ("Unexpected ZeroTermsQuery: " <> show q)
2547instance ToJSON MatchQueryType where
2548 toJSON MatchPhrase = "phrase"
2549 toJSON MatchPhrasePrefix = "phrase_prefix"
2551instance FromJSON MatchQueryType where
2552 parseJSON = withText "MatchQueryType" parse
2553 where parse "phrase" = pure MatchPhrase
2554 parse "phrase_prefix" = pure MatchPhrasePrefix
2555 parse t = fail ("Unexpected MatchQueryType: " <> show t)
2557instance FromJSON Status where
2558 parseJSON (Object v) = Status <$>
2559 v .:? "ok" <*>
2560 v .: "status" <*>
2561 v .: "name" <*>
2562 v .: "version" <*>
2563 v .: "tagline"
2564 parseJSON _ = empty
2567instance ToJSON IndexSettings where
2568 toJSON (IndexSettings s r) = object ["settings" .=
2569 object ["index" .=
2570 object ["number_of_shards" .= s, "number_of_replicas" .= r]
2574instance ToJSON IndexTemplate where
2575 toJSON (IndexTemplate p s m) = merge
2576 (object [ "template" .= p
2577 , "mappings" .= foldl' merge (object []) m
2578 ])
2579 (toJSON s)
2580 where
2581 merge (Object o1) (Object o2) = toJSON $ HM.union o1 o2
2582 merge o Null = o
2583 merge _ _ = undefined
2585instance (FromJSON a) => FromJSON (EsResult a) where
2586 parseJSON jsonVal@(Object v) = do
2587 found <- v .:? "found" .!= False
2588 fr <- if found
2589 then parseJSON jsonVal
2590 else return Nothing
2591 EsResult <$> v .: "_index" <*>
2592 v .: "_type" <*>
2593 v .: "_id" <*>
2594 pure fr
2595 parseJSON _ = empty
2597instance (FromJSON a) => FromJSON (EsResultFound a) where
2598 parseJSON (Object v) = EsResultFound <$>
2599 v .: "_version" <*>
2600 v .: "_source"
2601 parseJSON _ = empty
2603instance FromJSON EsError where
2604 parseJSON (Object v) = EsError <$>
2605 v .: "status" <*>
2606 v .: "error"
2607 parseJSON _ = empty
2609instance FromJSON IndexAliasesSummary where
2610 parseJSON = withObject "IndexAliasesSummary" parse
2611 where parse o = IndexAliasesSummary . mconcat <$> mapM (uncurry go) (HM.toList o)
2612 go ixn = withObject "index aliases" $ \ia -> do
2613 aliases <- ia .: "aliases"
2614 forM (HM.toList aliases) $ \(aName, v) -> do
2615 let indexAlias = IndexAlias (IndexName ixn) (IndexAliasName (IndexName aName))
2616 IndexAliasSummary indexAlias <$> parseJSON v
2619instance ToJSON IndexAliasAction where
2620 toJSON (AddAlias ia opts) = object ["add" .= (iaObj <> optsObj)]
2621 where Object iaObj = toJSON ia
2622 Object optsObj = toJSON opts
2623 toJSON (RemoveAlias ia) = object ["remove" .= iaObj]
2624 where Object iaObj = toJSON ia
2626instance ToJSON IndexAlias where
2627 toJSON IndexAlias {..} = object ["index" .= srcIndex
2628 , "alias" .= indexAlias
2631instance ToJSON IndexAliasCreate where
2632 toJSON IndexAliasCreate {..} = Object (filterObj <> routingObj)
2633 where filterObj = maybe mempty (HM.singleton "filter" . toJSON) aliasCreateFilter
2634 Object routingObj = maybe (Object mempty) toJSON aliasCreateRouting
2636instance ToJSON AliasRouting where
2637 toJSON (AllAliasRouting v) = object ["routing" .= v]
2638 toJSON (GranularAliasRouting srch idx) = object (catMaybes prs)
2639 where prs = [("search_routing" .=) <$> srch
2640 ,("index_routing" .=) <$> idx]
2642instance FromJSON AliasRouting where
2643 parseJSON = withObject "AliasRouting" parse
2644 where parse o = parseAll o <|> parseGranular o
2645 parseAll o = AllAliasRouting <$> o .: "routing"
2646 parseGranular o = do
2647 sr <- o .:? "search_routing"
2648 ir <- o .:? "index_routing"
2649 if isNothing sr && isNothing ir
2650 then fail "Both search_routing and index_routing can't be blank"
2651 else return (GranularAliasRouting sr ir)
2653instance FromJSON IndexAliasCreate where
2654 parseJSON v = withObject "IndexAliasCreate" parse v
2655 where parse o = IndexAliasCreate <$> optional (parseJSON v)
2656 <*> o .:? "filter"
2658instance ToJSON SearchAliasRouting where
2659 toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
2661instance FromJSON SearchAliasRouting where
2662 parseJSON = withText "SearchAliasRouting" parse
2663 where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
2665instance ToJSON Search where
2666 toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
2667 omitNulls [ "query" .= query
2668 , "filter" .= sFilter
2669 , "sort" .= sort
2670 , "aggregations" .= searchAggs
2671 , "highlight" .= highlight
2672 , "from" .= sFrom
2673 , "size" .= sSize
2674 , "track_scores" .= sTrackSortScores
2675 , "fields" .= sFields
2676 , "_source" .= sSource]
2679instance ToJSON Source where
2680 toJSON NoSource = toJSON False
2681 toJSON (SourcePatterns patterns) = toJSON patterns
2682 toJSON (SourceIncludeExclude incl excl) = object [ "include" .= incl, "exclude" .= excl ]
2684instance ToJSON PatternOrPatterns where
2685 toJSON (PopPattern pattern) = toJSON pattern
2686 toJSON (PopPatterns patterns) = toJSON patterns
2688instance ToJSON Include where
2689 toJSON (Include patterns) = toJSON patterns
2691instance ToJSON Exclude where
2692 toJSON (Exclude patterns) = toJSON patterns
2694instance ToJSON Pattern where
2695 toJSON (Pattern pattern) = toJSON pattern
2698instance ToJSON FieldHighlight where
2699 toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =
2700 object [ fName .= fSettings ]
2701 toJSON (FieldHighlight (FieldName fName) Nothing) =
2702 object [ fName .= emptyObject ]
2704instance ToJSON Highlights where
2705 toJSON (Highlights global fields) =
2706 omitNulls (("fields" .= fields)
2707 : highlightSettingsPairs global)
2709instance ToJSON HighlightSettings where
2710 toJSON hs = omitNulls (highlightSettingsPairs (Just hs))
2712highlightSettingsPairs :: Maybe HighlightSettings -> [Pair]
2713highlightSettingsPairs Nothing = []
2714highlightSettingsPairs (Just (Plain plh)) = plainHighPairs (Just plh)
2715highlightSettingsPairs (Just (Postings ph)) = postHighPairs (Just ph)
2716highlightSettingsPairs (Just (FastVector fvh)) = fastVectorHighPairs (Just fvh)
2719plainHighPairs :: Maybe PlainHighlight -> [Pair]
2720plainHighPairs Nothing = []
2721plainHighPairs (Just (PlainHighlight plCom plNonPost)) =
2722 [ "type" .= String "plain"]
2723 ++ commonHighlightPairs plCom
2724 ++ nonPostingsToPairs plNonPost
2726postHighPairs :: Maybe PostingsHighlight -> [Pair]
2727postHighPairs Nothing = []
2728postHighPairs (Just (PostingsHighlight pCom)) =
2729 ("type" .= String "postings")
2730 : commonHighlightPairs pCom
2732fastVectorHighPairs :: Maybe FastVectorHighlight -> [Pair]
2733fastVectorHighPairs Nothing = []
2734fastVectorHighPairs (Just
2735 (FastVectorHighlight fvCom fvNonPostSettings fvBoundChars
2736 fvBoundMaxScan fvFragOff fvMatchedFields
2737 fvPhraseLim)) =
2738 [ "type" .= String "fvh"
2739 , "boundary_chars" .= fvBoundChars
2740 , "boundary_max_scan" .= fvBoundMaxScan
2741 , "fragment_offset" .= fvFragOff
2742 , "matched_fields" .= fvMatchedFields
2743 , "phraseLimit" .= fvPhraseLim]
2744 ++ commonHighlightPairs fvCom
2745 ++ nonPostingsToPairs fvNonPostSettings
2747deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
2748deleteSeveral ks hm = foldr HM.delete hm ks
2750commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
2751commonHighlightPairs Nothing = []
2752commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
2753 chNoMatchSize chHighlightQuery
2754 chRequireFieldMatch)) =
2755 [ "order" .= chScore
2756 , "force_source" .= chForceSource
2757 , "encoder" .= chEncoder
2758 , "no_match_size" .= chNoMatchSize
2759 , "highlight_query" .= chHighlightQuery
2760 , "require_fieldMatch" .= chRequireFieldMatch]
2761 ++ highlightTagToPairs chTag
2764nonPostingsToPairs :: Maybe NonPostings -> [Pair]
2765nonPostingsToPairs Nothing = []
2766nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
2767 [ "fragment_size" .= npFragSize
2768 , "number_of_fragments" .= npNumOfFrags]
2770parseNEJSON :: (FromJSON a) => [Value] -> Parser (NonEmpty a)
2771parseNEJSON [] = fail "Expected non-empty list"
2772parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
2775instance ToJSON HighlightEncoder where
2776 toJSON DefaultEncoder = String "default"
2777 toJSON HTMLEncoder = String "html"
2779highlightTagToPairs :: Maybe HighlightTag -> [Pair]
2780highlightTagToPairs (Just (TagSchema _)) = [ "scheme" .= String "default"]
2781highlightTagToPairs (Just (CustomTags (pre, post))) = [ "pre_tags" .= pre
2782 , "post_tags" .= post]
2783highlightTagToPairs Nothing = []
2785instance ToJSON SortSpec where
2786 toJSON (DefaultSortSpec
2787 (DefaultSort (FieldName dsSortFieldName) dsSortOrder dsIgnoreUnmapped
2788 dsSortMode dsMissingSort dsNestedFilter)) =
2789 object [dsSortFieldName .= omitNulls base] where
2790 base = [ "order" .= dsSortOrder
2791 , "ignore_unmapped" .= dsIgnoreUnmapped
2792 , "mode" .= dsSortMode
2793 , "missing" .= dsMissingSort
2794 , "nested_filter" .= dsNestedFilter ]
2796 toJSON (GeoDistanceSortSpec gdsSortOrder (GeoPoint (FieldName field) gdsLatLon) units) =
2797 object [ "unit" .= units
2798 , field .= gdsLatLon
2799 , "order" .= gdsSortOrder ]
2802instance ToJSON SortOrder where
2803 toJSON Ascending = String "asc"
2804 toJSON Descending = String "desc"
2807instance ToJSON SortMode where
2808 toJSON SortMin = String "min"
2809 toJSON SortMax = String "max"
2810 toJSON SortSum = String "sum"
2811 toJSON SortAvg = String "avg"
2814instance ToJSON Missing where
2815 toJSON LastMissing = String "_last"
2816 toJSON FirstMissing = String "_first"
2817 toJSON (CustomMissing txt) = String txt
2820instance ToJSON ScoreType where
2821 toJSON ScoreTypeMax = "max"
2822 toJSON ScoreTypeAvg = "avg"
2823 toJSON ScoreTypeSum = "sum"
2824 toJSON ScoreTypeNone = "none"
2826instance FromJSON ScoreType where
2827 parseJSON = withText "ScoreType" parse
2828 where parse "max" = pure ScoreTypeMax
2829 parse "avg" = pure ScoreTypeAvg
2830 parse "sum" = pure ScoreTypeSum
2831 parse "none" = pure ScoreTypeNone
2832 parse t = fail ("Unexpected ScoreType: " <> show t)
2834instance ToJSON Distance where
2835 toJSON (Distance dCoefficient dUnit) =
2836 String boltedTogether where
2837 coefText = showText dCoefficient
2838 (String unitText) = toJSON dUnit
2839 boltedTogether = mappend coefText unitText
2841instance FromJSON Distance where
2842 parseJSON = withText "Distance" parse
2843 where parse t = Distance <$> parseCoeff nT
2844 <*> parseJSON (String unitT)
2845 where (nT, unitT) = T.span validForNumber t
2846 -- may be a better way to do this
2847 validForNumber '-' = True
2848 validForNumber '.' = True
2849 validForNumber 'e' = True
2850 validForNumber c = isNumber c
2851 parseCoeff "" = fail "Empty string cannot be parsed as number"
2852 parseCoeff s = return (read (T.unpack s))
2854instance ToJSON DistanceUnit where
2855 toJSON Miles = String "mi"
2856 toJSON Yards = String "yd"
2857 toJSON Feet = String "ft"
2858 toJSON Inches = String "in"
2859 toJSON Kilometers = String "km"
2860 toJSON Meters = String "m"
2861 toJSON Centimeters = String "cm"
2862 toJSON Millimeters = String "mm"
2863 toJSON NauticalMiles = String "nmi"
2866instance FromJSON DistanceUnit where
2867 parseJSON = withText "DistanceUnit" parse
2868 where parse "mi" = pure Miles
2869 parse "yd" = pure Yards
2870 parse "ft" = pure Feet
2871 parse "in" = pure Inches
2872 parse "km" = pure Kilometers
2873 parse "m" = pure Meters
2874 parse "cm" = pure Centimeters
2875 parse "mm" = pure Millimeters
2876 parse "nmi" = pure NauticalMiles
2877 parse u = fail ("Unrecognized DistanceUnit: " <> show u)
2879instance ToJSON DistanceType where
2880 toJSON Arc = String "arc"
2881 toJSON SloppyArc = String "sloppy_arc"
2882 toJSON Plane = String "plane"
2884instance FromJSON DistanceType where
2885 parseJSON = withText "DistanceType" parse
2886 where parse "arc" = pure Arc
2887 parse "sloppy_arc" = pure SloppyArc
2888 parse "plane" = pure Plane
2889 parse t = fail ("Unrecognized DistanceType: " <> show t)
2892instance ToJSON OptimizeBbox where
2893 toJSON NoOptimizeBbox = String "none"
2894 toJSON (OptimizeGeoFilterType gft) = toJSON gft
2896instance FromJSON OptimizeBbox where
2897 parseJSON v = withText "NoOptimizeBbox" parseNoOptimize v
2898 <|> parseOptimize v
2899 where parseNoOptimize "none" = pure NoOptimizeBbox
2900 parseNoOptimize _ = mzero
2901 parseOptimize = fmap OptimizeGeoFilterType . parseJSON
2903instance ToJSON GeoBoundingBoxConstraint where
2904 toJSON (GeoBoundingBoxConstraint
2905 (FieldName gbbcGeoBBField) gbbcConstraintBox cache type') =
2906 object [gbbcGeoBBField .= gbbcConstraintBox
2907 , "_cache" .= cache
2908 , "type" .= type']
2910instance FromJSON GeoBoundingBoxConstraint where
2911 parseJSON = withObject "GeoBoundingBoxConstraint" parse
2912 where parse o = case HM.toList (deleteSeveral ["type", "_cache"] o) of
2913 [(fn, v)] -> GeoBoundingBoxConstraint (FieldName fn)
2914 <$> parseJSON v
2915 <*> o .:? "_cache" .!= defaultCache
2916 <*> o .: "type"
2917 _ -> fail "Could not find field name for GeoBoundingBoxConstraint"
2919instance ToJSON GeoFilterType where
2920 toJSON GeoFilterMemory = String "memory"
2921 toJSON GeoFilterIndexed = String "indexed"
2923instance FromJSON GeoFilterType where
2924 parseJSON = withText "GeoFilterType" parse
2925 where parse "memory" = pure GeoFilterMemory
2926 parse "indexed" = pure GeoFilterIndexed
2927 parse t = fail ("Unrecognized GeoFilterType: " <> show t)
2929instance ToJSON GeoBoundingBox where
2930 toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
2931 object ["top_left" .= gbbTopLeft
2932 , "bottom_right" .= gbbBottomRight]
2934instance FromJSON GeoBoundingBox where
2935 parseJSON = withObject "GeoBoundingBox" parse
2936 where parse o = GeoBoundingBox
2937 <$> o .: "top_left"
2938 <*> o .: "bottom_right"
2940instance ToJSON LatLon where
2941 toJSON (LatLon lLat lLon) =
2942 object ["lat" .= lLat
2943 , "lon" .= lLon]
2945instance FromJSON LatLon where
2946 parseJSON = withObject "LatLon" parse
2947 where parse o = LatLon <$> o .: "lat"
2948 <*> o .: "lon"
2950-- index for smaller ranges, fielddata for longer ranges
2951instance ToJSON RangeExecution where
2952 toJSON RangeExecutionIndex = "index"
2953 toJSON RangeExecutionFielddata = "fielddata"
2956instance FromJSON RangeExecution where
2957 parseJSON = withText "RangeExecution" parse
2958 where parse "index" = pure RangeExecutionIndex
2959 parse "fielddata" = pure RangeExecutionFielddata
2960 parse t = error ("Unrecognized RangeExecution " <> show t)
2962instance ToJSON RegexpFlags where
2963 toJSON AllRegexpFlags = String "ALL"
2964 toJSON NoRegexpFlags = String "NONE"
2965 toJSON (SomeRegexpFlags (h :| fs)) = String $ T.intercalate "|" flagStrs
2966 where flagStrs = map flagStr . nub $ h:fs
2967 flagStr AnyString = "ANYSTRING"
2968 flagStr Automaton = "AUTOMATON"
2969 flagStr Complement = "COMPLEMENT"
2970 flagStr Empty = "EMPTY"
2971 flagStr Intersection = "INTERSECTION"
2972 flagStr Interval = "INTERVAL"
2974instance FromJSON RegexpFlags where
2975 parseJSON = withText "RegexpFlags" parse
2976 where parse "ALL" = pure AllRegexpFlags
2977 parse "NONE" = pure NoRegexpFlags
2978 parse t = SomeRegexpFlags <$> parseNEJSON (String <$> T.splitOn "|" t)
2980instance FromJSON RegexpFlag where
2981 parseJSON = withText "RegexpFlag" parse
2982 where parse "ANYSTRING" = pure AnyString
2983 parse "AUTOMATON" = pure Automaton
2984 parse "COMPLEMENT" = pure Complement
2985 parse "EMPTY" = pure Empty
2986 parse "INTERSECTION" = pure Intersection
2987 parse "INTERVAL" = pure Interval
2988 parse f = fail ("Unknown RegexpFlag: " <> show f)
2990instance ToJSON Term where
2991 toJSON (Term field value) = object ["term" .= object
2992 [field .= value]]
2994instance FromJSON Term where
2995 parseJSON = withObject "Term" parse
2996 where parse o = do termObj <- o .: "term"
2997 case HM.toList termObj of
2998 [(fn, v)] -> Term fn <$> parseJSON v
2999 _ -> fail "Expected object with 1 field-named key"
3001instance ToJSON BoolMatch where
3002 toJSON (MustMatch term cache) = object ["must" .= term,
3003 "_cache" .= cache]
3004 toJSON (MustNotMatch term cache) = object ["must_not" .= term,
3005 "_cache" .= cache]
3006 toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
3007 "_cache" .= cache]
3009instance FromJSON BoolMatch where
3010 parseJSON = withObject "BoolMatch" parse
3011 where parse o = mustMatch `taggedWith` "must"
3012 <|> mustNotMatch `taggedWith` "must_not"
3013 <|> shouldMatch `taggedWith` "should"
3014 where taggedWith parser k = parser =<< o .: k
3015 mustMatch t = MustMatch t <$> o .:? "_cache" .!= defaultCache
3016 mustNotMatch t = MustNotMatch t <$> o .:? "_cache" .!= defaultCache
3017 shouldMatch t = ShouldMatch t <$> o .:? "_cache" .!= defaultCache
3019instance (FromJSON a) => FromJSON (SearchResult a) where
3020 parseJSON (Object v) = SearchResult <$>
3021 v .: "took" <*>
3022 v .: "timed_out" <*>
3023 v .: "_shards" <*>
3024 v .: "hits" <*>
3025 v .:? "aggregations" <*>
3026 v .:? "_scroll_id"
3027 parseJSON _ = empty
3029instance (FromJSON a) => FromJSON (SearchHits a) where
3030 parseJSON (Object v) = SearchHits <$>
3031 v .: "total" <*>
3032 v .: "max_score" <*>
3033 v .: "hits"
3034 parseJSON _ = empty
3036instance (FromJSON a) => FromJSON (Hit a) where
3037 parseJSON (Object v) = Hit <$>
3038 v .: "_index" <*>
3039 v .: "_type" <*>
3040 v .: "_id" <*>
3041 v .: "_score" <*>
3042 v .:? "_source" <*>
3043 v .:? "highlight"
3044 parseJSON _ = empty
3046instance FromJSON ShardResult where
3047 parseJSON (Object v) = ShardResult <$>
3048 v .: "total" <*>
3049 v .: "successful" <*>
3050 v .: "failed"
3051 parseJSON _ = empty
3054instance FromJSON DocVersion where
3055 parseJSON v = do
3056 i <- parseJSON v
3057 maybe (fail "DocVersion out of range") return $ mkDocVersion i
3059instance Bounded DocVersion where
3060 minBound = DocVersion 1
3061 maxBound = DocVersion 9200000000000000000 -- 9.2e+18
3063instance Enum DocVersion where
3064 succ x
3065 | x /= maxBound = DocVersion (succ $ docVersionNumber x)
3066 | otherwise = succError "DocVersion"
3067 pred x
3068 | x /= minBound = DocVersion (pred $ docVersionNumber x)
3069 | otherwise = predError "DocVersion"
3070 toEnum i =
3071 fromMaybe (error $ show i ++ " out of DocVersion range") $ mkDocVersion i
3072 fromEnum = docVersionNumber
3073 enumFrom = boundedEnumFrom
3074 enumFromThen = boundedEnumFromThen