git.iko.soy/typeable/bloodhound
on master help sign in
Merge remote-tracking branch 'origin/index-aliases'
commitd1b4b7cd25cd1727b91ad44268b66ce7375a09c3 authorChris Allen <cma@bitemyapp.com> dateSat 14 Nov 2015, 21:35 (11 years ago) parentdf776d42612b75
4 files changed+1217−244
bloodhound.cabal+5−2 src/Database/Bloodhound/Client.hs+56 src/Database/Bloodhound/Types.hs+780−196 tests/tests.hs+376−46
bloodhound.cabal+5−2
@@ -45,7 +45,8 @@ library
4545 data-default-class,
4646 blaze-builder,
4747 unordered-containers,
48− mtl-compat
48+ mtl-compat,
49+ hashable
4950 default-language: Haskell2010
5051
5152test-suite tests
@@ -68,7 +69,9 @@ test-suite tests
6869 vector,
6970 unordered-containers >= 0.2.5.0 && <0.3,
7071 mtl,
71− quickcheck-properties
72+ quickcheck-properties,
73+ derive,
74+ quickcheck-instances
7275 default-language: Haskell2010
7376
7477test-suite doctests
src/Database/Bloodhound/Client.hs+56
@@ -27,6 +27,8 @@ module Database.Bloodhound.Client
2727 , indexExists
2828 , openIndex
2929 , closeIndex
30+ , updateIndexAliases
31+ , getIndexAliases
3032 , putTemplate
3133 , templateExists
3234 , deleteTemplate
@@ -55,6 +57,7 @@ module Database.Bloodhound.Client
5557 , isVersionConflict
5658 , isSuccess
5759 , isCreated
60+ , parseEsResponse
5861 )
5962 where
6063
@@ -66,8 +69,10 @@ import Control.Monad.IO.Class
6669import Data.Aeson
6770import Data.ByteString.Lazy.Builder
6871import qualified Data.ByteString.Lazy.Char8 as L
72+import Data.Foldable (toList)
6973import Data.Ix
7074import qualified Data.List as LS (filter)
75+import Data.List.NonEmpty (NonEmpty (..))
7176import Data.Maybe (fromMaybe, isJust)
7277import Data.Monoid
7378import Data.Text (Text)
@@ -279,6 +284,28 @@ existentialQuery url = do
279284 reply <- head url
280285 return (reply, respIsTwoHunna reply)
281286
287+
288+-- | Tries to parse a response body as the expected type @a@ and
289+-- failing that tries to parse it as an EsError. All well-formed, JSON
290+-- responses from elasticsearch should fall into these two
291+-- categories. If they don't, a 'StatusCodeException' will be thrown.
292+parseEsResponse :: (MonadBH m, MonadThrow m, FromJSON a) => Reply
293+ -> m (Either EsError a)
294+parseEsResponse reply
295+ | respIsTwoHunna reply = case eitherDecode body of
296+ Right a -> return (Right a)
297+ Left _ -> tryParseError
298+ | otherwise = tryParseError
299+ where body = responseBody reply
300+ stat = responseStatus reply
301+ hdrs = responseHeaders reply
302+ cookies = responseCookieJar reply
303+ tryParseError = case eitherDecode body of
304+ Right e -> return (Left e)
305+ -- this case should not be possible
306+ Left _ -> explode
307+ explode = throwM (StatusCodeException stat hdrs cookies)
308+
282309-- | 'indexExists' enables you to check if an index exists. Returns 'Bool'
283310-- in IO
284311--
@@ -323,6 +350,35 @@ openIndex = openOrCloseIndexes OpenIndex
323350closeIndex :: MonadBH m => IndexName -> m Reply
324351closeIndex = openOrCloseIndexes CloseIndex
325352
353+
354+-- | 'updateIndexAliases' updates the server's index alias
355+-- table. Operations are atomic. Explained in further detail at
356+-- <https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html>
357+--
358+-- >>> let src = IndexName "a-real-index"
359+-- >>> let aliasName = IndexName "an-alias"
360+-- >>> let iAlias = IndexAlias src (IndexAliasName aliasName)
361+-- >>> let aliasCreate = IndexAliasCreate Nothing Nothing
362+-- >>> respIsTwoHunna <$> runBH' (createIndex defaultIndexSettings src)
363+-- True
364+-- >>> runBH' $ indexExists src
365+-- True
366+-- >>> respIsTwoHunna <$> runBH' (updateIndexAliases (AddAlias iAlias aliasCreate :| []))
367+-- True
368+-- >>> runBH' $ indexExists aliasName
369+-- True
370+updateIndexAliases :: MonadBH m => NonEmpty IndexAliasAction -> m Reply
371+updateIndexAliases actions = bindM2 post url (return body)
372+ where url = joinPath ["_aliases"]
373+ body = Just (encode bodyJSON)
374+ bodyJSON = object [ "actions" .= toList actions]
375+
376+-- | Get all aliases configured on the server.
377+getIndexAliases :: (MonadBH m, MonadThrow m)
378+ => m (Either EsError IndexAliasesSummary)
379+getIndexAliases = parseEsResponse =<< get =<< url
380+ where url = joinPath ["_aliases"]
381+
326382-- | 'putTemplate' creates a template given an 'IndexTemplate' and a 'TemplateName'.
327383-- Explained in further detail at
328384-- <https://www.elastic.co/guide/en/elasticsearch/reference/1.7/indices-templates.html>
src/Database/Bloodhound/Types.hs+780−196
@@ -1,8 +1,10 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
12{-# LANGUAGE DeriveGeneric #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE FlexibleInstances #-}
45{-# LANGUAGE GeneralizedNewtypeDeriving #-}
56{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE NoMonomorphismRestriction #-}
68{-# LANGUAGE OverloadedStrings #-}
79{-# LANGUAGE RecordWildCards #-}
810{-# LANGUAGE UndecidableInstances #-}
@@ -62,6 +64,16 @@ module Database.Bloodhound.Types
6264 , EsResult(..)
6365 , EsResultFound(..)
6466 , EsError(..)
67+ , IndexAlias(..)
68+ , IndexAliasName(..)
69+ , IndexAliasAction(..)
70+ , IndexAliasCreate(..)
71+ , IndexAliasSummary(..)
72+ , IndexAliasesSummary(..)
73+ , AliasRouting(..)
74+ , SearchAliasRouting(..)
75+ , IndexAliasRouting(..)
76+ , RoutingValue(..)
6577 , DocVersion
6678 , ExternalDocVersion(..)
6779 , VersionControl(..)
@@ -237,9 +249,12 @@ import Control.Monad.Reader
237249import Control.Monad.State
238250import Control.Monad.Writer
239251import Data.Aeson
240−import Data.Aeson.Types (Pair, emptyObject, parseMaybe)
252+import Data.Aeson.Types (Pair, Parser, emptyObject,
253+ parseMaybe)
241254import qualified Data.ByteString.Lazy.Char8 as L
242−import qualified Data.HashMap.Strict as HM (union)
255+import Data.Char
256+import Data.Hashable (Hashable)
257+import qualified Data.HashMap.Strict as HM
243258import Data.List (foldl', nub)
244259import Data.List.NonEmpty (NonEmpty (..), toList)
245260import qualified Data.Map.Strict as M
@@ -247,6 +262,8 @@ import Data.Maybe
247262import Data.Text (Text)
248263import qualified Data.Text as T
249264import Data.Time.Clock (UTCTime)
265+import qualified Data.Traversable as DT
266+import Data.Typeable (Typeable)
250267import qualified Data.Vector as V
251268import GHC.Enum
252269import GHC.Generics (Generic)
@@ -320,7 +337,7 @@ data Version = Version { number :: Text
320337 , build_hash :: Text
321338 , build_timestamp :: UTCTime
322339 , build_snapshot :: Bool
323− , lucene_version :: Text } deriving (Eq, Show, Generic)
340+ , lucene_version :: Text } deriving (Eq, Show, Generic, Typeable)
324341
325342{-| 'Status' is a data type for describing the JSON body returned by
326343 Elasticsearch when you query its status. This was deprecated in 1.2.0.
@@ -430,6 +447,33 @@ data EsResultFound a = EsResultFound { _version :: DocVersion
430447data EsError = EsError { errorStatus :: Int
431448 , errorMessage :: Text } deriving (Eq, Show)
432449
450+data IndexAlias = IndexAlias { srcIndex :: IndexName
451+ , indexAlias :: IndexAliasName } deriving (Eq, Show)
452+
453+newtype IndexAliasName = IndexAliasName { indexAliasName :: IndexName } deriving (Eq, Show, ToJSON)
454+
455+data IndexAliasAction = AddAlias IndexAlias IndexAliasCreate
456+ | RemoveAlias IndexAlias deriving (Show, Eq, Typeable)
457+
458+data IndexAliasCreate = IndexAliasCreate { aliasCreateRouting :: Maybe AliasRouting
459+ , aliasCreateFilter :: Maybe Filter}
460+ deriving (Show, Eq, Typeable)
461+
462+data AliasRouting = AllAliasRouting RoutingValue
463+ | GranularAliasRouting (Maybe SearchAliasRouting) (Maybe IndexAliasRouting)
464+ deriving (Show, Eq, Typeable)
465+
466+newtype SearchAliasRouting = SearchAliasRouting (NonEmpty RoutingValue) deriving (Show, Eq, Typeable)
467+
468+newtype IndexAliasRouting = IndexAliasRouting RoutingValue deriving (Show, Eq, ToJSON, FromJSON, Typeable)
469+
470+newtype RoutingValue = RoutingValue { routingValue :: Text } deriving (Show, Eq, ToJSON, FromJSON, Typeable)
471+
472+newtype IndexAliasesSummary = IndexAliasesSummary { indexAliasesSummary :: [IndexAliasSummary] } deriving (Show, Eq, Typeable)
473+
474+{-| 'IndexAliasSummary' is a summary of an index alias configured for a server. -}
475+data IndexAliasSummary = IndexAliasSummary { indexAliasSummaryAlias :: IndexAlias
476+ , indexAliasSummaryCreate :: IndexAliasCreate} deriving (Show, Eq)
433477
434478{-| 'DocVersion' is an integer version number for a document between 1
435479and 9.2e+18 used for <<https://www.elastic.co/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html optimistic concurrency control>>.
@@ -581,15 +625,15 @@ type PrefixValue = Text
581625{-| 'BooleanOperator' is the usual And/Or operators with an ES compatible
582626 JSON encoding baked in. Used all over the place.
583627-}
584−data BooleanOperator = And | Or deriving (Eq, Show)
628+data BooleanOperator = And | Or deriving (Eq, Show, Typeable)
585629
586630{-| 'ShardCount' is part of 'IndexSettings'
587631-}
588−newtype ShardCount = ShardCount Int deriving (Eq, Show, Generic)
632+newtype ShardCount = ShardCount Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
589633
590634{-| 'ReplicaCount' is part of 'IndexSettings'
591635-}
592−newtype ReplicaCount = ReplicaCount Int deriving (Eq, Show, Generic)
636+newtype ReplicaCount = ReplicaCount Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
593637
594638{-| 'Server' is used with the client functions to point at the ES instance
595639-}
@@ -597,35 +641,35 @@ newtype Server = Server Text deriving (Eq, Show)
597641
598642{-| 'IndexName' is used to describe which index to query/create/delete
599643-}
600−newtype IndexName = IndexName Text deriving (Eq, Generic, Show)
644+newtype IndexName = IndexName Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
601645
602646{-| 'TemplateName' is used to describe which template to query/create/delete
603647-}
604−newtype TemplateName = TemplateName Text deriving (Eq, Show, Generic)
648+newtype TemplateName = TemplateName Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
605649
606650{-| 'TemplatePattern' represents a pattern which is matched against index names
607651-}
608−newtype TemplatePattern = TemplatePattern Text deriving (Eq, Show, Generic)
652+newtype TemplatePattern = TemplatePattern Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
609653
610654{-| 'MappingName' is part of mappings which are how ES describes and schematizes
611655 the data in the indices.
612656-}
613−newtype MappingName = MappingName Text deriving (Eq, Generic, Show)
657+newtype MappingName = MappingName Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
614658
615659{-| 'DocId' is a generic wrapper value for expressing unique Document IDs.
616660 Can be set by the user or created by ES itself. Often used in client
617661 functions for poking at specific documents.
618662-}
619−newtype DocId = DocId Text deriving (Eq, Generic, Show)
663+newtype DocId = DocId Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
620664
621665{-| 'QueryString' is used to wrap query text bodies, be they human written or not.
622666-}
623−newtype QueryString = QueryString Text deriving (Eq, Generic, Show)
667+newtype QueryString = QueryString Text deriving (Eq, Generic, Show, ToJSON, FromJSON, Typeable)
624668
625669{-| 'FieldName' is used all over the place wherever a specific field within
626670 a document needs to be specified, usually in 'Query's or 'Filter's.
627671-}
628−newtype FieldName = FieldName Text deriving (Eq, Show)
672+newtype FieldName = FieldName Text deriving (Eq, Show, ToJSON, FromJSON, Typeable)
629673
630674
631675{-| 'Script' is often used in place of 'FieldName' to specify more
@@ -636,100 +680,98 @@ newtype Script = Script { scriptText :: Text } deriving (Eq, Show)
636680{-| 'CacheName' is used in 'RegexpFilter' for describing the
637681 'CacheKey' keyed caching behavior.
638682-}
639−newtype CacheName = CacheName Text deriving (Eq, Show)
683+newtype CacheName = CacheName Text deriving (Eq, Show, ToJSON, FromJSON, Typeable)
640684
641685{-| 'CacheKey' is used in 'RegexpFilter' to key regex caching.
642686-}
643687newtype CacheKey =
644− CacheKey Text deriving (Eq, Show)
688+ CacheKey Text deriving (Eq, Show, ToJSON, FromJSON, Typeable)
645689newtype Existence =
646− Existence Bool deriving (Eq, Show)
690+ Existence Bool deriving (Eq, Show, ToJSON, FromJSON, Typeable)
647691newtype NullValue =
648− NullValue Bool deriving (Eq, Show)
692+ NullValue Bool deriving (Eq, Show, ToJSON, FromJSON, Typeable)
649693newtype CutoffFrequency =
650− CutoffFrequency Double deriving (Eq, Show, Generic)
694+ CutoffFrequency Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
651695newtype Analyzer =
652− Analyzer Text deriving (Eq, Show, Generic)
696+ Analyzer Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
653697newtype MaxExpansions =
654− MaxExpansions Int deriving (Eq, Show, Generic)
698+ MaxExpansions Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
655699
656700{-| 'Lenient', if set to true, will cause format based failures to be
657701 ignored. I don't know what the bloody default is, Elasticsearch
658702 documentation didn't say what it was. Let me know if you figure it out.
659703-}
660704newtype Lenient =
661− Lenient Bool deriving (Eq, Show, Generic)
705+ Lenient Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
662706newtype Tiebreaker =
663− Tiebreaker Double deriving (Eq, Show, Generic)
707+ Tiebreaker Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
664708newtype Boost =
665− Boost Double deriving (Eq, Show, Generic)
709+ Boost Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
666710newtype BoostTerms =
667− BoostTerms Double deriving (Eq, Show, Generic)
711+ BoostTerms Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
668712
669713{-| 'MinimumMatch' controls how many should clauses in the bool query should
670714 match. Can be an absolute value (2) or a percentage (30%) or a
671715 combination of both.
672716-}
673717newtype MinimumMatch =
674− MinimumMatch Int deriving (Eq, Show, Generic)
675−newtype MinimumMatchText =
676− MinimumMatchText Text deriving (Eq, Show)
718+ MinimumMatch Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
677719newtype DisableCoord =
678− DisableCoord Bool deriving (Eq, Show, Generic)
720+ DisableCoord Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
679721newtype IgnoreTermFrequency =
680− IgnoreTermFrequency Bool deriving (Eq, Show, Generic)
722+ IgnoreTermFrequency Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
681723newtype MinimumTermFrequency =
682− MinimumTermFrequency Int deriving (Eq, Show, Generic)
724+ MinimumTermFrequency Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
683725newtype MaxQueryTerms =
684− MaxQueryTerms Int deriving (Eq, Show, Generic)
726+ MaxQueryTerms Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
685727newtype Fuzziness =
686− Fuzziness Double deriving (Eq, Show, Generic)
728+ Fuzziness Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
687729
688730{-| 'PrefixLength' is the prefix length used in queries, defaults to 0. -}
689731newtype PrefixLength =
690− PrefixLength Int deriving (Eq, Show, Generic)
732+ PrefixLength Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
691733newtype TypeName =
692− TypeName Text deriving (Eq, Show, Generic)
734+ TypeName Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
693735newtype PercentMatch =
694− PercentMatch Double deriving (Eq, Show, Generic)
736+ PercentMatch Double deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
695737newtype StopWord =
696− StopWord Text deriving (Eq, Show, Generic)
738+ StopWord Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
697739newtype QueryPath =
698− QueryPath Text deriving (Eq, Show, Generic)
740+ QueryPath Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
699741
700742{-| Allowing a wildcard at the beginning of a word (eg "*ing") is particularly
701743 heavy, because all terms in the index need to be examined, just in case
702744 they match. Leading wildcards can be disabled by setting
703745 'AllowLeadingWildcard' to false. -}
704746newtype AllowLeadingWildcard =
705− AllowLeadingWildcard Bool deriving (Eq, Show, Generic)
747+ AllowLeadingWildcard Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
706748newtype LowercaseExpanded =
707− LowercaseExpanded Bool deriving (Eq, Show, Generic)
749+ LowercaseExpanded Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
708750newtype EnablePositionIncrements =
709− EnablePositionIncrements Bool deriving (Eq, Show, Generic)
751+ EnablePositionIncrements Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
710752
711753{-| By default, wildcard terms in a query are not analyzed.
712754 Setting 'AnalyzeWildcard' to true enables best-effort analysis.
713755-}
714−newtype AnalyzeWildcard = AnalyzeWildcard Bool deriving (Eq, Show, Generic)
756+newtype AnalyzeWildcard = AnalyzeWildcard Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
715757
716758{-| 'GeneratePhraseQueries' defaults to false.
717759-}
718760newtype GeneratePhraseQueries =
719− GeneratePhraseQueries Bool deriving (Eq, Show, Generic)
761+ GeneratePhraseQueries Bool deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
720762
721763{-| 'Locale' is used for string conversions - defaults to ROOT.
722764-}
723−newtype Locale = Locale Text deriving (Eq, Show, Generic)
724−newtype MaxWordLength = MaxWordLength Int deriving (Eq, Show, Generic)
725−newtype MinWordLength = MinWordLength Int deriving (Eq, Show, Generic)
765+newtype Locale = Locale Text deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
766+newtype MaxWordLength = MaxWordLength Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
767+newtype MinWordLength = MinWordLength Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
726768
727769{-| 'PhraseSlop' sets the default slop for phrases, 0 means exact
728770 phrase matches. Default is 0.
729771-}
730−newtype PhraseSlop = PhraseSlop Int deriving (Eq, Show, Generic)
731−newtype MinDocFrequency = MinDocFrequency Int deriving (Eq, Show, Generic)
732−newtype MaxDocFrequency = MaxDocFrequency Int deriving (Eq, Show, Generic)
772+newtype PhraseSlop = PhraseSlop Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
773+newtype MinDocFrequency = MinDocFrequency Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
774+newtype MaxDocFrequency = MaxDocFrequency Int deriving (Eq, Show, Generic, ToJSON, FromJSON, Typeable)
733775
734776{-| 'unpackId' is a silly convenience function that gets used once.
735777-}
@@ -832,7 +874,7 @@ data HighlightTag = TagSchema Text
832874
833875data Query =
834876 TermQuery Term (Maybe Boost)
835− | TermsQuery (NonEmpty Term)
877+ | TermsQuery Text (NonEmpty Text)
836878 | QueryMatchQuery MatchQuery
837879 | QueryMultiMatchQuery MultiMatchQuery
838880 | QueryBoolQuery BoolQuery
@@ -858,19 +900,19 @@ data Query =
858900 | QuerySimpleQueryStringQuery SimpleQueryStringQuery
859901 | QueryRangeQuery RangeQuery
860902 | QueryRegexpQuery RegexpQuery
861− deriving (Eq, Show)
903+ deriving (Eq, Show, Typeable)
862904
863905data RegexpQuery =
864906 RegexpQuery { regexpQueryField :: FieldName
865907 , regexpQuery :: Regexp
866908 , regexpQueryFlags :: RegexpFlags
867909 , regexpQueryBoost :: Maybe Boost
868− } deriving (Eq, Show)
910+ } deriving (Eq, Show, Typeable)
869911
870912data RangeQuery =
871913 RangeQuery { rangeQueryField :: FieldName
872914 , rangeQueryRange :: RangeValue
873− , rangeQueryBoost :: Boost } deriving (Eq, Show)
915+ , rangeQueryBoost :: Boost } deriving (Eq, Show, Typeable)
874916
875917mkRangeQuery :: FieldName -> RangeValue -> RangeQuery
876918mkRangeQuery f r = RangeQuery f r (Boost 1.0)
@@ -881,10 +923,10 @@ data SimpleQueryStringQuery =
881923 , simpleQueryStringField :: Maybe FieldOrFields
882924 , simpleQueryStringOperator :: Maybe BooleanOperator
883925 , simpleQueryStringAnalyzer :: Maybe Analyzer
884− , simpleQueryStringFlags :: Maybe [SimpleQueryFlag]
926+ , simpleQueryStringFlags :: Maybe (NonEmpty SimpleQueryFlag)
885927 , simpleQueryStringLowercaseExpanded :: Maybe LowercaseExpanded
886928 , simpleQueryStringLocale :: Maybe Locale
887− } deriving (Eq, Show)
929+ } deriving (Eq, Show, Typeable)
888930
889931data SimpleQueryFlag =
890932 SimpleQueryAll
@@ -898,7 +940,7 @@ data SimpleQueryFlag =
898940 | SimpleQueryWhitespace
899941 | SimpleQueryFuzzy
900942 | SimpleQueryNear
901− | SimpleQuerySlop deriving (Eq, Show)
943+ | SimpleQuerySlop deriving (Eq, Show, Typeable)
902944
903945-- use_dis_max and tie_breaker when fields are plural?
904946data QueryStringQuery =
@@ -920,7 +962,7 @@ data QueryStringQuery =
920962 , queryStringMinimumShouldMatch :: Maybe MinimumMatch
921963 , queryStringLenient :: Maybe Lenient
922964 , queryStringLocale :: Maybe Locale
923− } deriving (Eq, Show)
965+ } deriving (Eq, Show, Typeable)
924966
925967mkQueryStringQuery :: QueryString -> QueryStringQuery
926968mkQueryStringQuery qs =
@@ -931,19 +973,19 @@ mkQueryStringQuery qs =
931973 Nothing Nothing
932974
933975data FieldOrFields = FofField FieldName
934− | FofFields [FieldName] deriving (Eq, Show)
976+ | FofFields (NonEmpty FieldName) deriving (Eq, Show, Typeable)
935977
936978data PrefixQuery =
937979 PrefixQuery
938980 { prefixQueryField :: FieldName
939981 , prefixQueryPrefixValue :: Text
940− , prefixQueryBoost :: Maybe Boost } deriving (Eq, Show)
982+ , prefixQueryBoost :: Maybe Boost } deriving (Eq, Show, Typeable)
941983
942984data NestedQuery =
943985 NestedQuery
944986 { nestedQueryPath :: QueryPath
945987 , nestedQueryScoreType :: ScoreType
946− , nestedQuery :: Query } deriving (Eq, Show)
988+ , nestedQuery :: Query } deriving (Eq, Show, Typeable)
947989
948990data MoreLikeThisFieldQuery =
949991 MoreLikeThisFieldQuery
@@ -953,7 +995,7 @@ data MoreLikeThisFieldQuery =
953995 , moreLikeThisFieldPercentMatch :: Maybe PercentMatch
954996 , moreLikeThisFieldMinimumTermFreq :: Maybe MinimumTermFrequency
955997 , moreLikeThisFieldMaxQueryTerms :: Maybe MaxQueryTerms
956− , moreLikeThisFieldStopWords :: Maybe [StopWord]
998+ , moreLikeThisFieldStopWords :: Maybe (NonEmpty StopWord)
957999 , moreLikeThisFieldMinDocFrequency :: Maybe MinDocFrequency
9581000 , moreLikeThisFieldMaxDocFrequency :: Maybe MaxDocFrequency
9591001 , moreLikeThisFieldMinWordLength :: Maybe MinWordLength
@@ -961,17 +1003,17 @@ data MoreLikeThisFieldQuery =
9611003 , moreLikeThisFieldBoostTerms :: Maybe BoostTerms
9621004 , moreLikeThisFieldBoost :: Maybe Boost
9631005 , moreLikeThisFieldAnalyzer :: Maybe Analyzer
964− } deriving (Eq, Show)
1006+ } deriving (Eq, Show, Typeable)
9651007
9661008data MoreLikeThisQuery =
9671009 MoreLikeThisQuery
9681010 { moreLikeThisText :: Text
969− , moreLikeThisFields :: Maybe [FieldName]
1011+ , moreLikeThisFields :: Maybe (NonEmpty FieldName)
9701012 -- default 0.3 (30%)
9711013 , moreLikeThisPercentMatch :: Maybe PercentMatch
9721014 , moreLikeThisMinimumTermFreq :: Maybe MinimumTermFrequency
9731015 , moreLikeThisMaxQueryTerms :: Maybe MaxQueryTerms
974− , moreLikeThisStopWords :: Maybe [StopWord]
1016+ , moreLikeThisStopWords :: Maybe (NonEmpty StopWord)
9751017 , moreLikeThisMinDocFrequency :: Maybe MinDocFrequency
9761018 , moreLikeThisMaxDocFrequency :: Maybe MaxDocFrequency
9771019 , moreLikeThisMinWordLength :: Maybe MinWordLength
@@ -979,32 +1021,32 @@ data MoreLikeThisQuery =
9791021 , moreLikeThisBoostTerms :: Maybe BoostTerms
9801022 , moreLikeThisBoost :: Maybe Boost
9811023 , moreLikeThisAnalyzer :: Maybe Analyzer
982− } deriving (Eq, Show)
1024+ } deriving (Eq, Show, Typeable)
9831025
9841026data IndicesQuery =
9851027 IndicesQuery
9861028 { indicesQueryIndices :: [IndexName]
9871029 , indicesQuery :: Query
9881030 -- default "all"
989− , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Show)
1031+ , indicesQueryNoMatch :: Maybe Query } deriving (Eq, Show, Typeable)
9901032
9911033data HasParentQuery =
9921034 HasParentQuery
9931035 { hasParentQueryType :: TypeName
9941036 , hasParentQuery :: Query
995− , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Show)
1037+ , hasParentQueryScoreType :: Maybe ScoreType } deriving (Eq, Show, Typeable)
9961038
9971039data HasChildQuery =
9981040 HasChildQuery
9991041 { hasChildQueryType :: TypeName
10001042 , hasChildQuery :: Query
1001− , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Show)
1043+ , hasChildQueryScoreType :: Maybe ScoreType } deriving (Eq, Show, Typeable)
10021044
10031045data ScoreType =
10041046 ScoreTypeMax
10051047 | ScoreTypeSum
10061048 | ScoreTypeAvg
1007− | ScoreTypeNone deriving (Eq, Show)
1049+ | ScoreTypeNone deriving (Eq, Show, Typeable)
10081050
10091051data FuzzyQuery =
10101052 FuzzyQuery { fuzzyQueryField :: FieldName
@@ -1013,7 +1055,7 @@ data FuzzyQuery =
10131055 , fuzzyQueryMaxExpansions :: MaxExpansions
10141056 , fuzzyQueryFuzziness :: Fuzziness
10151057 , fuzzyQueryBoost :: Maybe Boost
1016− } deriving (Eq, Show)
1058+ } deriving (Eq, Show, Typeable)
10171059
10181060data FuzzyLikeFieldQuery =
10191061 FuzzyLikeFieldQuery
@@ -1026,7 +1068,7 @@ data FuzzyLikeFieldQuery =
10261068 , fuzzyLikeFieldPrefixLength :: PrefixLength
10271069 , fuzzyLikeFieldBoost :: Boost
10281070 , fuzzyLikeFieldAnalyzer :: Maybe Analyzer
1029− } deriving (Eq, Show)
1071+ } deriving (Eq, Show, Typeable)
10301072
10311073data FuzzyLikeThisQuery =
10321074 FuzzyLikeThisQuery
@@ -1038,19 +1080,19 @@ data FuzzyLikeThisQuery =
10381080 , fuzzyLikePrefixLength :: PrefixLength
10391081 , fuzzyLikeBoost :: Boost
10401082 , fuzzyLikeAnalyzer :: Maybe Analyzer
1041− } deriving (Eq, Show)
1083+ } deriving (Eq, Show, Typeable)
10421084
10431085data FilteredQuery =
10441086 FilteredQuery
10451087 { filteredQuery :: Query
1046− , filteredFilter :: Filter } deriving (Eq, Show)
1088+ , filteredFilter :: Filter } deriving (Eq, Show, Typeable)
10471089
10481090data DisMaxQuery =
10491091 DisMaxQuery { disMaxQueries :: [Query]
10501092 -- default 0.0
10511093 , disMaxTiebreaker :: Tiebreaker
10521094 , disMaxBoost :: Maybe Boost
1053− } deriving (Eq, Show)
1095+ } deriving (Eq, Show, Typeable)
10541096
10551097data MatchQuery =
10561098 MatchQuery { matchQueryField :: FieldName
@@ -1062,7 +1104,7 @@ data MatchQuery =
10621104 , matchQueryAnalyzer :: Maybe Analyzer
10631105 , matchQueryMaxExpansions :: Maybe MaxExpansions
10641106 , matchQueryLenient :: Maybe Lenient
1065− , matchQueryBoost :: Maybe Boost } deriving (Eq, Show)
1107+ , matchQueryBoost :: Maybe Boost } deriving (Eq, Show, Typeable)
10661108
10671109{-| 'mkMatchQuery' is a convenience function that defaults the less common parameters,
10681110 enabling you to provide only the 'FieldName' and 'QueryString' to make a 'MatchQuery'
@@ -1072,7 +1114,7 @@ mkMatchQuery field query = MatchQuery field query Or ZeroTermsNone Nothing Nothi
10721114
10731115data MatchQueryType =
10741116 MatchPhrase
1075− | MatchPhrasePrefix deriving (Eq, Show)
1117+ | MatchPhrasePrefix deriving (Eq, Show, Typeable)
10761118
10771119data MultiMatchQuery =
10781120 MultiMatchQuery { multiMatchQueryFields :: [FieldName]
@@ -1084,7 +1126,7 @@ data MultiMatchQuery =
10841126 , multiMatchQueryCutoffFrequency :: Maybe CutoffFrequency
10851127 , multiMatchQueryAnalyzer :: Maybe Analyzer
10861128 , multiMatchQueryMaxExpansions :: Maybe MaxExpansions
1087− , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Show)
1129+ , multiMatchQueryLenient :: Maybe Lenient } deriving (Eq, Show, Typeable)
10881130
10891131{-| 'mkMultiMatchQuery' is a convenience function that defaults the less common parameters,
10901132 enabling you to provide only the list of 'FieldName's and 'QueryString' to
@@ -1101,7 +1143,7 @@ data MultiMatchQueryType =
11011143 | MultiMatchMostFields
11021144 | MultiMatchCrossFields
11031145 | MultiMatchPhrase
1104− | MultiMatchPhrasePrefix deriving (Eq, Show)
1146+ | MultiMatchPhrasePrefix deriving (Eq, Show, Typeable)
11051147
11061148data BoolQuery =
11071149 BoolQuery { boolQueryMustMatch :: [Query]
@@ -1110,7 +1152,7 @@ data BoolQuery =
11101152 , boolQueryMinimumShouldMatch :: Maybe MinimumMatch
11111153 , boolQueryBoost :: Maybe Boost
11121154 , boolQueryDisableCoord :: Maybe DisableCoord
1113− } deriving (Eq, Show)
1155+ } deriving (Eq, Show, Typeable)
11141156
11151157mkBoolQuery :: [Query] -> [Query] -> [Query] -> BoolQuery
11161158mkBoolQuery must mustNot should =
@@ -1119,7 +1161,7 @@ mkBoolQuery must mustNot should =
11191161data BoostingQuery =
11201162 BoostingQuery { positiveQuery :: Query
11211163 , negativeQuery :: Query
1122− , negativeBoost :: Boost } deriving (Eq, Show)
1164+ , negativeBoost :: Boost } deriving (Eq, Show, Typeable)
11231165
11241166data CommonTermsQuery =
11251167 CommonTermsQuery { commonField :: FieldName
@@ -1131,16 +1173,16 @@ data CommonTermsQuery =
11311173 , commonBoost :: Maybe Boost
11321174 , commonAnalyzer :: Maybe Analyzer
11331175 , commonDisableCoord :: Maybe DisableCoord
1134− } deriving (Eq, Show)
1176+ } deriving (Eq, Show, Typeable)
11351177
11361178data CommonMinimumMatch =
11371179 CommonMinimumMatchHighLow MinimumMatchHighLow
11381180 | CommonMinimumMatch MinimumMatch
1139− deriving (Eq, Show)
1181+ deriving (Eq, Show, Typeable)
11401182
11411183data MinimumMatchHighLow =
11421184 MinimumMatchHighLow { lowFreq :: MinimumMatch
1143− , highFreq :: MinimumMatch } deriving (Eq, Show)
1185+ , highFreq :: MinimumMatch } deriving (Eq, Show, Typeable)
11441186
11451187data Filter = AndFilter [Filter] Cache
11461188 | OrFilter [Filter] Cache
@@ -1160,15 +1202,15 @@ data Filter = AndFilter [Filter] Cache
11601202 | RangeFilter FieldName RangeValue RangeExecution Cache
11611203 | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
11621204 | TermFilter Term Cache
1163− deriving (Eq, Show)
1205+ deriving (Eq, Show, Typeable)
11641206
11651207data ZeroTermsQuery = ZeroTermsNone
1166− | ZeroTermsAll deriving (Eq, Show)
1208+ | ZeroTermsAll deriving (Eq, Show, Typeable)
11671209
11681210data RangeExecution = RangeExecutionIndex
1169− | RangeExecutionFielddata deriving (Eq, Show)
1211+ | RangeExecutionFielddata deriving (Eq, Show, Typeable)
11701212
1171−newtype Regexp = Regexp Text deriving (Eq, Show)
1213+newtype Regexp = Regexp Text deriving (Eq, Show, FromJSON)
11721214
11731215data RegexpFlags = AllRegexpFlags
11741216 | NoRegexpFlags
@@ -1229,33 +1271,33 @@ rangeValueToPair rv = case rv of
12291271 RangeDoubleGtLt (GreaterThan l) (LessThan g) -> ["gt" .= l, "lt" .= g]
12301272
12311273data Term = Term { termField :: Text
1232− , termValue :: Text } deriving (Eq, Show)
1274+ , termValue :: Text } deriving (Eq, Show, Typeable)
12331275
12341276data BoolMatch = MustMatch Term Cache
12351277 | MustNotMatch Term Cache
1236− | ShouldMatch [Term] Cache deriving (Eq, Show)
1278+ | ShouldMatch [Term] Cache deriving (Eq, Show, Typeable)
12371279
12381280-- "memory" or "indexed"
12391281data GeoFilterType = GeoFilterMemory
1240− | GeoFilterIndexed deriving (Eq, Show)
1282+ | GeoFilterIndexed deriving (Eq, Show, Typeable)
12411283
12421284data LatLon = LatLon { lat :: Double
1243− , lon :: Double } deriving (Eq, Show)
1285+ , lon :: Double } deriving (Eq, Show, Typeable)
12441286
12451287data GeoBoundingBox =
12461288 GeoBoundingBox { topLeft :: LatLon
1247− , bottomRight :: LatLon } deriving (Eq, Show)
1289+ , bottomRight :: LatLon } deriving (Eq, Show, Typeable)
12481290
12491291data GeoBoundingBoxConstraint =
12501292 GeoBoundingBoxConstraint { geoBBField :: FieldName
12511293 , constraintBox :: GeoBoundingBox
12521294 , bbConstraintcache :: Cache
12531295 , geoType :: GeoFilterType
1254− } deriving (Eq, Show)
1296+ } deriving (Eq, Show, Typeable)
12551297
12561298data GeoPoint =
12571299 GeoPoint { geoField :: FieldName
1258− , latLon :: LatLon} deriving (Eq, Show)
1300+ , latLon :: LatLon} deriving (Eq, Show, Typeable)
12591301
12601302data DistanceUnit = Miles
12611303 | Yards
@@ -1265,18 +1307,18 @@ data DistanceUnit = Miles
12651307 | Meters
12661308 | Centimeters
12671309 | Millimeters
1268− | NauticalMiles deriving (Eq, Show)
1310+ | NauticalMiles deriving (Eq, Show, Typeable)
12691311
12701312data DistanceType = Arc
12711313 | SloppyArc -- doesn't exist <1.0
1272− | Plane deriving (Eq, Show)
1314+ | Plane deriving (Eq, Show, Typeable)
12731315
12741316data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
1275− | NoOptimizeBbox deriving (Eq, Show)
1317+ | NoOptimizeBbox deriving (Eq, Show, Typeable)
12761318
12771319data Distance =
12781320 Distance { coefficient :: Double
1279− , unit :: DistanceUnit } deriving (Eq, Show)
1321+ , unit :: DistanceUnit } deriving (Eq, Show, Typeable)
12801322
12811323data DistanceRange =
12821324 DistanceRange { distanceFrom :: Distance
@@ -1409,6 +1451,22 @@ mkTermsScriptAggregation t = TermsAggregation (Right t) Nothing Nothing Nothing
14091451mkDateHistogram :: FieldName -> Interval -> DateHistogramAggregation
14101452mkDateHistogram t i = DateHistogramAggregation t i Nothing Nothing Nothing Nothing Nothing Nothing
14111453
1454+instance 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]
1460+
1461+instance 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"
1469+
14121470instance ToJSON TermOrder where
14131471 toJSON (TermOrder termSortField termSortOrder) = object [termSortField .= termSortOrder]
14141472
@@ -1641,6 +1699,94 @@ instance ToJSON Filter where
16411699 , "_cache" .= cache
16421700 , "_cache_key" .= cacheKey]]
16431701
1702+instance 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"
1763+
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"
1784+
1785+fieldTagged :: Monad m => (FieldName -> Object -> m a) -> Object -> m a
1786+fieldTagged f o = case HM.toList o of
1787+ [(k, Object o')] -> f (FieldName k) o'
1788+ _ -> fail "Expected object with 1 field-named key"
1789+
16441790instance ToJSON GeoPoint where
16451791 toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
16461792 object [ geoPointField .= geoPointLatLon ]
@@ -1655,12 +1801,9 @@ instance ToJSON Query where
16551801 boosted = maybe [] (return . ("boost" .=)) boost
16561802 merged = mappend base boosted
16571803
1658− toJSON (TermsQuery terms) =
1804+ toJSON (TermsQuery fieldName terms) =
16591805 object [ "terms" .= object conjoined ]
1660− where conjoined = [ getTermsField terms .=
1661− fmap (toJSON . getTermValue) (toList terms)]
1662− getTermsField ((Term f _ ) :| _) = f
1663− getTermValue (Term _ v) = v
1806+ where conjoined = [fieldName .= terms]
16641807 toJSON (IdsQuery idsQueryMappingName docIds) =
16651808 object [ "ids" .= object conjoined ]
16661809 where conjoined = [ "type" .= idsQueryMappingName
@@ -1685,12 +1828,12 @@ instance ToJSON Query where
16851828 object [ "common" .= commonTermsQuery ]
16861829
16871830 toJSON (ConstantScoreFilter csFilter boost) =
1688− object [ "constant_score" .= csFilter
1689− , "boost" .= boost]
1831+ object ["constant_score" .= object ["filter" .= csFilter
1832+ , "boost" .= boost]]
16901833
16911834 toJSON (ConstantScoreQuery query boost) =
1692− object [ "constant_score" .= query
1693− , "boost" .= boost]
1835+ object ["constant_score" .= object ["query" .= query
1836+ , "boost" .= boost]]
16941837
16951838 toJSON (QueryDisMaxQuery disMaxQuery) =
16961839 object [ "dis_max" .= disMaxQuery ]
@@ -1740,6 +1883,77 @@ instance ToJSON Query where
17401883 toJSON (QuerySimpleQueryStringQuery query) =
17411884 object [ "simple_query_string" .= query ]
17421885
1886+instance 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
1956+
17431957
17441958omitNulls :: [(Text, Value)] -> Value
17451959omitNulls = object . filter notNull where
@@ -1759,6 +1973,17 @@ instance ToJSON SimpleQueryStringQuery where
17591973 , "lowercase_expanded_terms" .= simpleQueryStringLowercaseExpanded
17601974 , "locale" .= simpleQueryStringLocale ]
17611975
1976+instance 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
17621987
17631988instance ToJSON FieldOrFields where
17641989 toJSON (FofField fieldName) =
@@ -1766,6 +1991,10 @@ instance ToJSON FieldOrFields where
17661991 toJSON (FofFields fieldNames) =
17671992 toJSON fieldNames
17681993
1994+instance FromJSON FieldOrFields where
1995+ parseJSON v = FofField <$> parseJSON v
1996+ <|> FofFields <$> (parseNEJSON =<< parseJSON v)
1997+
17691998instance ToJSON SimpleQueryFlag where
17701999 toJSON SimpleQueryAll = "ALL"
17712000 toJSON SimpleQueryNone = "NONE"
@@ -1780,6 +2009,21 @@ instance ToJSON SimpleQueryFlag where
17802009 toJSON SimpleQueryNear = "NEAR"
17812010 toJSON SimpleQuerySlop = "SLOP"
17822011
2012+instance 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)
17832027
17842028instance ToJSON RegexpQuery where
17852029 toJSON (RegexpQuery (FieldName rqQueryField)
@@ -1790,6 +2034,13 @@ instance ToJSON RegexpQuery where
17902034 , "flags" .= rqQueryFlags
17912035 , "boost" .= rqQueryBoost ]
17922036
2037+instance 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"
17932044
17942045instance ToJSON QueryStringQuery where
17952046 toJSON (QueryStringQuery qsQueryString
@@ -1821,12 +2072,71 @@ instance ToJSON QueryStringQuery where
18212072 , "lenient" .= qsLenient
18222073 , "locale" .= qsLocale ]
18232074
2075+instance 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"
18242095
18252096instance ToJSON RangeQuery where
18262097 toJSON (RangeQuery (FieldName fieldName) range boost) =
1827− object [ fieldName .= conjoined ]
2098+ object [ fieldName .= object conjoined ]
18282099 where conjoined = [ "boost" .= boost ] ++ (rangeValueToPair range)
18292100
2101+instance FromJSON RangeQuery where
2102+ parseJSON = withObject "RangeQuery" parse
2103+ where parse = fieldTagged $ \fn o ->
2104+ RangeQuery fn
2105+ <$> parseJSON (Object o)
2106+ <*> o .: "boost"
2107+
2108+instance 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
18302140
18312141instance ToJSON PrefixQuery where
18322142 toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
@@ -1834,6 +2144,12 @@ instance ToJSON PrefixQuery where
18342144 where base = [ "value" .= queryValue
18352145 , "boost" .= boost ]
18362146
2147+instance FromJSON PrefixQuery where
2148+ parseJSON = withObject "PrefixQuery" parse
2149+ where parse = fieldTagged $ \fn o ->
2150+ PrefixQuery fn
2151+ <$> o .: "value"
2152+ <*> o .:? "boost"
18372153
18382154instance ToJSON NestedQuery where
18392155 toJSON (NestedQuery nqPath nqScoreType nqQuery) =
@@ -1841,6 +2157,12 @@ instance ToJSON NestedQuery where
18412157 , "score_mode" .= nqScoreType
18422158 , "query" .= nqQuery ]
18432159
2160+instance FromJSON NestedQuery where
2161+ parseJSON = withObject "NestedQuery" parse
2162+ where parse o = NestedQuery
2163+ <$> o .: "path"
2164+ <*> o .: "score_mode"
2165+ <*> o .: "query"
18442166
18452167instance ToJSON MoreLikeThisFieldQuery where
18462168 toJSON (MoreLikeThisFieldQuery text (FieldName fieldName)
@@ -1860,6 +2182,24 @@ instance ToJSON MoreLikeThisFieldQuery where
18602182 , "boost" .= boost
18612183 , "analyzer" .= analyzer ]
18622184
2185+instance 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)
18632203
18642204instance ToJSON MoreLikeThisQuery where
18652205 toJSON (MoreLikeThisQuery text fields percent
@@ -1880,6 +2220,23 @@ instance ToJSON MoreLikeThisQuery where
18802220 , "boost" .= boost
18812221 , "analyzer" .= analyzer ]
18822222
2223+instance 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)
18832240
18842241instance ToJSON IndicesQuery where
18852242 toJSON (IndicesQuery indices query noMatch) =
@@ -1887,6 +2244,12 @@ instance ToJSON IndicesQuery where
18872244 , "no_match_query" .= noMatch
18882245 , "query" .= query ]
18892246
2247+instance FromJSON IndicesQuery where
2248+ parseJSON = withObject "IndicesQuery" parse
2249+ where parse o = IndicesQuery
2250+ <$> o .:? "indices" .!= []
2251+ <*> o .: "query"
2252+ <*> o .:? "no_match_query"
18902253
18912254instance ToJSON HasParentQuery where
18922255 toJSON (HasParentQuery queryType query scoreType) =
@@ -1894,6 +2257,12 @@ instance ToJSON HasParentQuery where
18942257 , "score_type" .= scoreType
18952258 , "query" .= query ]
18962259
2260+instance FromJSON HasParentQuery where
2261+ parseJSON = withObject "HasParentQuery" parse
2262+ where parse o = HasParentQuery
2263+ <$> o .: "parent_type"
2264+ <*> o .: "query"
2265+ <*> o .:? "score_type"
18972266
18982267instance ToJSON HasChildQuery where
18992268 toJSON (HasChildQuery queryType query scoreType) =
@@ -1901,6 +2270,12 @@ instance ToJSON HasChildQuery where
19012270 , "score_type" .= scoreType
19022271 , "type" .= queryType ]
19032272
2273+instance FromJSON HasChildQuery where
2274+ parseJSON = withObject "HasChildQuery" parse
2275+ where parse o = HasChildQuery
2276+ <$> o .: "type"
2277+ <*> o .: "query"
2278+ <*> o .:? "score_type"
19042279
19052280instance ToJSON FuzzyQuery where
19062281 toJSON (FuzzyQuery (FieldName fieldName) queryText
@@ -1912,6 +2287,15 @@ instance ToJSON FuzzyQuery where
19122287 , "boost" .= boost
19132288 , "max_expansions" .= maxEx ]
19142289
2290+instance 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"
19152299
19162300instance ToJSON FuzzyLikeFieldQuery where
19172301 toJSON (FuzzyLikeFieldQuery (FieldName fieldName)
@@ -1926,6 +2310,17 @@ instance ToJSON FuzzyLikeFieldQuery where
19262310 , "analyzer" .= analyzer
19272311 , "boost" .= boost ]]
19282312
2313+instance 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"
19292324
19302325instance ToJSON FuzzyLikeThisQuery where
19312326 toJSON (FuzzyLikeThisQuery fields text maxTerms
@@ -1940,12 +2335,28 @@ instance ToJSON FuzzyLikeThisQuery where
19402335 , "analyzer" .= analyzer
19412336 , "boost" .= boost ]
19422337
2338+instance 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"
19432349
19442350instance ToJSON FilteredQuery where
19452351 toJSON (FilteredQuery query fFilter) =
19462352 object [ "query" .= query
19472353 , "filter" .= fFilter ]
19482354
2355+instance FromJSON FilteredQuery where
2356+ parseJSON = withObject "FilteredQuery" parse
2357+ where parse o = FilteredQuery
2358+ <$> o .: "query"
2359+ <*> o .: "filter"
19492360
19502361instance ToJSON DisMaxQuery where
19512362 toJSON (DisMaxQuery queries tiebreaker boost) =
@@ -1954,6 +2365,12 @@ instance ToJSON DisMaxQuery where
19542365 , "boost" .= boost
19552366 , "tie_breaker" .= tiebreaker ]
19562367
2368+instance FromJSON DisMaxQuery where
2369+ parseJSON = withObject "DisMaxQuery" parse
2370+ where parse o = DisMaxQuery
2371+ <$> o .:? "queries" .!= []
2372+ <*> o .: "tie_breaker"
2373+ <*> o .:? "boost"
19572374
19582375instance ToJSON CommonTermsQuery where
19592376 toJSON (CommonTermsQuery (FieldName fieldName)
@@ -1969,6 +2386,18 @@ instance ToJSON CommonTermsQuery where
19692386 , "disable_coord" .= disableCoord
19702387 , "high_freq_operator" .= hfo ]
19712388
2389+instance 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"
19722401
19732402instance ToJSON CommonMinimumMatch where
19742403 toJSON (CommonMinimumMatch mm) = toJSON mm
@@ -1976,12 +2405,28 @@ instance ToJSON CommonMinimumMatch where
19762405 object [ "low_freq" .= lowF
19772406 , "high_freq" .= highF ]
19782407
2408+instance 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")
2416+
2417+
19792418instance ToJSON BoostingQuery where
19802419 toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
19812420 object [ "positive" .= bqPositiveQuery
19822421 , "negative" .= bqNegativeQuery
19832422 , "negative_boost" .= bqNegativeBoost ]
19842423
2424+instance FromJSON BoostingQuery where
2425+ parseJSON = withObject "BoostingQuery" parse
2426+ where parse o = BoostingQuery
2427+ <$> o .: "positive"
2428+ <*> o .: "negative"
2429+ <*> o .: "negative_boost"
19852430
19862431instance ToJSON BoolQuery where
19872432 toJSON (BoolQuery mustM notM shouldM bqMin boost disableCoord) =
@@ -1993,6 +2438,15 @@ instance ToJSON BoolQuery where
19932438 , "boost" .= boost
19942439 , "disable_coord" .= disableCoord ]
19952440
2441+instance 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"
19962450
19972451instance ToJSON MatchQuery where
19982452 toJSON (MatchQuery (FieldName fieldName)
@@ -2010,6 +2464,19 @@ instance ToJSON MatchQuery where
20102464 , "lenient" .= lenient
20112465 , "boost" .= boost ]
20122466
2467+instance 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"
20132480
20142481instance ToJSON MultiMatchQuery where
20152482 toJSON (MultiMatchQuery fields (QueryString query) boolOp
@@ -2026,6 +2493,20 @@ instance ToJSON MultiMatchQuery where
20262493 , "max_expansions" .= maxEx
20272494 , "lenient" .= lenient ]
20282495
2496+instance 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"
20292510
20302511instance ToJSON MultiMatchQueryType where
20312512 toJSON MultiMatchBestFields = "best_fields"
@@ -2034,107 +2515,44 @@ instance ToJSON MultiMatchQueryType where
20342515 toJSON MultiMatchPhrase = "phrase"
20352516 toJSON MultiMatchPhrasePrefix = "phrase_prefix"
20362517
2518+instance 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)
2526+
20372527instance ToJSON BooleanOperator where
20382528 toJSON And = String "and"
20392529 toJSON Or = String "or"
20402530
2531+instance 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)
2536+
20412537instance ToJSON ZeroTermsQuery where
20422538 toJSON ZeroTermsNone = String "none"
20432539 toJSON ZeroTermsAll = String "all"
20442540
2541+instance 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)
2546+
20452547instance ToJSON MatchQueryType where
20462548 toJSON MatchPhrase = "phrase"
20472549 toJSON MatchPhrasePrefix = "phrase_prefix"
20482550
2049−instance ToJSON FieldName where
2050− toJSON (FieldName fieldName) = String fieldName
2051−
2052−instance ToJSON ReplicaCount where
2053− toJSON = genericToJSON defaultOptions
2054−instance ToJSON ShardCount where
2055− toJSON = genericToJSON defaultOptions
2056−instance ToJSON CutoffFrequency where
2057− toJSON = genericToJSON defaultOptions
2058−instance ToJSON Analyzer where
2059− toJSON = genericToJSON defaultOptions
2060−instance ToJSON MaxExpansions where
2061− toJSON = genericToJSON defaultOptions
2062−instance ToJSON Lenient where
2063− toJSON = genericToJSON defaultOptions
2064−instance ToJSON Boost where
2065− toJSON = genericToJSON defaultOptions
2066−instance ToJSON Version where
2067− toJSON = genericToJSON defaultOptions
2068−instance ToJSON Tiebreaker where
2069− toJSON = genericToJSON defaultOptions
2070−instance ToJSON MinimumMatch where
2071− toJSON = genericToJSON defaultOptions
2072−instance ToJSON DisableCoord where
2073− toJSON = genericToJSON defaultOptions
2074−instance ToJSON PrefixLength where
2075− toJSON = genericToJSON defaultOptions
2076−instance ToJSON Fuzziness where
2077− toJSON = genericToJSON defaultOptions
2078−instance ToJSON IgnoreTermFrequency where
2079− toJSON = genericToJSON defaultOptions
2080−instance ToJSON MaxQueryTerms where
2081− toJSON = genericToJSON defaultOptions
2082−instance ToJSON TypeName where
2083− toJSON = genericToJSON defaultOptions
2084−instance ToJSON IndexName where
2085− toJSON = genericToJSON defaultOptions
2086−instance ToJSON TemplateName where
2087− toJSON = genericToJSON defaultOptions
2088−instance ToJSON TemplatePattern where
2089− toJSON = genericToJSON defaultOptions
2090−instance ToJSON BoostTerms where
2091− toJSON = genericToJSON defaultOptions
2092−instance ToJSON MaxWordLength where
2093− toJSON = genericToJSON defaultOptions
2094−instance ToJSON MinWordLength where
2095− toJSON = genericToJSON defaultOptions
2096−instance ToJSON MaxDocFrequency where
2097− toJSON = genericToJSON defaultOptions
2098−instance ToJSON MinDocFrequency where
2099− toJSON = genericToJSON defaultOptions
2100−instance ToJSON PhraseSlop where
2101− toJSON = genericToJSON defaultOptions
2102−instance ToJSON StopWord where
2103− toJSON = genericToJSON defaultOptions
2104−instance ToJSON QueryPath where
2105− toJSON = genericToJSON defaultOptions
2106−instance ToJSON MinimumTermFrequency where
2107− toJSON = genericToJSON defaultOptions
2108−instance ToJSON PercentMatch where
2109− toJSON = genericToJSON defaultOptions
2110−instance ToJSON MappingName where
2111− toJSON = genericToJSON defaultOptions
2112−instance ToJSON DocId where
2113− toJSON = genericToJSON defaultOptions
2114−instance ToJSON QueryString where
2115− toJSON = genericToJSON defaultOptions
2116−instance ToJSON AllowLeadingWildcard where
2117− toJSON = genericToJSON defaultOptions
2118−instance ToJSON LowercaseExpanded where
2119− toJSON = genericToJSON defaultOptions
2120−instance ToJSON AnalyzeWildcard where
2121− toJSON = genericToJSON defaultOptions
2122−instance ToJSON GeneratePhraseQueries where
2123− toJSON = genericToJSON defaultOptions
2124−instance ToJSON Locale where
2125− toJSON = genericToJSON defaultOptions
2126−instance ToJSON EnablePositionIncrements where
2127− toJSON = genericToJSON defaultOptions
2128−
2129−instance FromJSON Version where
2130− parseJSON = genericParseJSON defaultOptions
2131−instance FromJSON IndexName where
2132− parseJSON = genericParseJSON defaultOptions
2133−instance FromJSON MappingName where
2134− parseJSON = genericParseJSON defaultOptions
2135−instance FromJSON DocId where
2136− parseJSON = genericParseJSON defaultOptions
2137−
2551+instance 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)
21382556
21392557instance FromJSON Status where
21402558 parseJSON (Object v) = Status <$>
@@ -2188,6 +2606,62 @@ instance FromJSON EsError where
21882606 v .: "error"
21892607 parseJSON _ = empty
21902608
2609+instance 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
2617+
2618+
2619+instance 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
2625+
2626+instance ToJSON IndexAlias where
2627+ toJSON IndexAlias {..} = object ["index" .= srcIndex
2628+ , "alias" .= indexAlias
2629+ ]
2630+
2631+instance 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
2635+
2636+instance 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]
2641+
2642+instance 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)
2652+
2653+instance FromJSON IndexAliasCreate where
2654+ parseJSON v = withObject "IndexAliasCreate" parse v
2655+ where parse o = IndexAliasCreate <$> optional (parseJSON v)
2656+ <*> o .:? "filter"
2657+
2658+instance ToJSON SearchAliasRouting where
2659+ toJSON (SearchAliasRouting rvs) = toJSON (T.intercalate "," (routingValue <$> toList rvs))
2660+
2661+instance FromJSON SearchAliasRouting where
2662+ parseJSON = withText "SearchAliasRouting" parse
2663+ where parse t = SearchAliasRouting <$> parseNEJSON (String <$> T.splitOn "," t)
2664+
21912665instance ToJSON Search where
21922666 toJSON (Search query sFilter sort searchAggs highlight sTrackSortScores sFrom sSize _ sFields sSource) =
21932667 omitNulls [ "query" .= query
@@ -2270,6 +2744,9 @@ fastVectorHighPairs (Just
22702744 ++ commonHighlightPairs fvCom
22712745 ++ nonPostingsToPairs fvNonPostSettings
22722746
2747+deleteSeveral :: (Eq k, Hashable k) => [k] -> HM.HashMap k v -> HM.HashMap k v
2748+deleteSeveral ks hm = foldr HM.delete hm ks
2749+
22732750commonHighlightPairs :: Maybe CommonHighlight -> [Pair]
22742751commonHighlightPairs Nothing = []
22752752commonHighlightPairs (Just (CommonHighlight chScore chForceSource chTag chEncoder
@@ -2290,6 +2767,9 @@ nonPostingsToPairs (Just (NonPostings npFragSize npNumOfFrags)) =
22902767 [ "fragment_size" .= npFragSize
22912768 , "number_of_fragments" .= npNumOfFrags]
22922769
2770+parseNEJSON :: (FromJSON a) => [Value] -> Parser (NonEmpty a)
2771+parseNEJSON [] = fail "Expected non-empty list"
2772+parseNEJSON (x:xs) = DT.mapM parseJSON (x :| xs)
22932773
22942774
22952775instance ToJSON HighlightEncoder where
@@ -2343,6 +2823,13 @@ instance ToJSON ScoreType where
23432823 toJSON ScoreTypeSum = "sum"
23442824 toJSON ScoreTypeNone = "none"
23452825
2826+instance 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)
23462833
23472834instance ToJSON Distance where
23482835 toJSON (Distance dCoefficient dUnit) =
@@ -2351,6 +2838,18 @@ instance ToJSON Distance where
23512838 (String unitText) = toJSON dUnit
23522839 boltedTogether = mappend coefText unitText
23532840
2841+instance 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))
23542853
23552854instance ToJSON DistanceUnit where
23562855 toJSON Miles = String "mi"
@@ -2364,16 +2863,42 @@ instance ToJSON DistanceUnit where
23642863 toJSON NauticalMiles = String "nmi"
23652864
23662865
2866+instance 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)
2878+
23672879instance ToJSON DistanceType where
23682880 toJSON Arc = String "arc"
23692881 toJSON SloppyArc = String "sloppy_arc"
23702882 toJSON Plane = String "plane"
23712883
2884+instance 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)
2890+
23722891
23732892instance ToJSON OptimizeBbox where
23742893 toJSON NoOptimizeBbox = String "none"
23752894 toJSON (OptimizeGeoFilterType gft) = toJSON gft
23762895
2896+instance 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
23772902
23782903instance ToJSON GeoBoundingBoxConstraint where
23792904 toJSON (GeoBoundingBoxConstraint
@@ -2382,23 +2907,45 @@ instance ToJSON GeoBoundingBoxConstraint where
23822907 , "_cache" .= cache
23832908 , "type" .= type']
23842909
2910+instance 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"
23852918
23862919instance ToJSON GeoFilterType where
23872920 toJSON GeoFilterMemory = String "memory"
23882921 toJSON GeoFilterIndexed = String "indexed"
23892922
2923+instance 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)
23902928
23912929instance ToJSON GeoBoundingBox where
23922930 toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
23932931 object ["top_left" .= gbbTopLeft
23942932 , "bottom_right" .= gbbBottomRight]
23952933
2934+instance FromJSON GeoBoundingBox where
2935+ parseJSON = withObject "GeoBoundingBox" parse
2936+ where parse o = GeoBoundingBox
2937+ <$> o .: "top_left"
2938+ <*> o .: "bottom_right"
23962939
23972940instance ToJSON LatLon where
23982941 toJSON (LatLon lLat lLon) =
23992942 object ["lat" .= lLat
24002943 , "lon" .= lLon]
24012944
2945+instance FromJSON LatLon where
2946+ parseJSON = withObject "LatLon" parse
2947+ where parse o = LatLon <$> o .: "lat"
2948+ <*> o .: "lon"
24022949
24032950-- index for smaller ranges, fielddata for longer ranges
24042951instance ToJSON RangeExecution where
@@ -2406,6 +2953,12 @@ instance ToJSON RangeExecution where
24062953 toJSON RangeExecutionFielddata = "fielddata"
24072954
24082955
2956+instance 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)
2961+
24092962instance ToJSON RegexpFlags where
24102963 toJSON AllRegexpFlags = String "ALL"
24112964 toJSON NoRegexpFlags = String "NONE"
@@ -2418,10 +2971,32 @@ instance ToJSON RegexpFlags where
24182971 flagStr Intersection = "INTERSECTION"
24192972 flagStr Interval = "INTERVAL"
24202973
2974+instance 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)
2979+
2980+instance 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)
2989+
24212990instance ToJSON Term where
24222991 toJSON (Term field value) = object ["term" .= object
24232992 [field .= value]]
24242993
2994+instance 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"
24253000
24263001instance ToJSON BoolMatch where
24273002 toJSON (MustMatch term cache) = object ["must" .= term,
@@ -2431,6 +3006,15 @@ instance ToJSON BoolMatch where
24313006 toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
24323007 "_cache" .= cache]
24333008
3009+instance 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
24343018
24353019instance (FromJSON a) => FromJSON (SearchResult a) where
24363020 parseJSON (Object v) = SearchResult <$>
tests/tests.hs+376−46
@@ -1,6 +1,8 @@
1−{-# LANGUAGE DeriveGeneric #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE ScopedTypeVariables #-}
1+{-# LANGUAGE DeriveGeneric #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
5+{-# LANGUAGE TemplateHaskell #-}
46{-# OPTIONS_GHC -fno-warn-orphans #-}
57module Main where
68
@@ -9,21 +11,26 @@ import Control.Exception
911import Control.Monad
1012import Control.Monad.Reader
1113import Data.Aeson
14+import Data.Aeson.Types (parseEither)
15+import Data.DeriveTH
1216import qualified Data.HashMap.Strict as HM
1317import Data.List (nub)
18+import qualified Data.List as L
1419import Data.List.NonEmpty (NonEmpty (..))
1520import qualified Data.List.NonEmpty as NE
1621import qualified Data.Map.Strict as M
1722import Data.Monoid
23+import Data.Proxy
1824import Data.Text (Text)
1925import qualified Data.Text as T
2026import Data.Time.Calendar (Day (..))
2127import Data.Time.Clock (UTCTime (..),
2228 secondsToDiffTime)
29+import Data.Typeable
2330import qualified Data.Vector as V
2431import Database.Bloodhound
2532import GHC.Generics (Generic)
26−import Network.HTTP.Client
33+import Network.HTTP.Client hiding (Proxy)
2734import qualified Network.HTTP.Types.Status as NHTS
2835import Prelude hiding (filter)
2936import Test.Hspec
@@ -31,6 +38,7 @@ import Test.QuickCheck.Property.Monoid (T (..), eq, prop_Monoid)
3138
3239import Test.Hspec.QuickCheck (prop)
3340import Test.QuickCheck
41+import Test.QuickCheck.Instances ()
3442
3543testServer :: Server
3644testServer = Server "http://localhost:9200"
@@ -101,6 +109,12 @@ is v = testServerBranch >>= \x -> return $ x == Just (serverBranch v)
101109when' :: Monad m => m Bool -> m () -> m ()
102110when' b f = b >>= \x -> when x f
103111
112+propJSON :: forall a. (Arbitrary a, ToJSON a, FromJSON a, Show a, Eq a, Typeable a) => Proxy a -> Spec
113+propJSON _ = prop testName $ \(a :: a) ->
114+ parseEither parseJSON (toJSON a) === Right a
115+ where testName = show ty <> " FromJSON/ToJSON roundtrips"
116+ ty = typeOf (undefined :: a)
117+
104118data Location = Location { lat :: Double
105119 , lon :: Double } deriving (Eq, Generic, Show)
106120
@@ -197,15 +211,15 @@ insertWithSpaceInId = do
197211 _ <- refreshIndex testIndex
198212 return ()
199213
200−searchTweet :: Search -> BH IO (Either String Tweet)
214+searchTweet :: Search -> BH IO (Either EsError Tweet)
201215searchTweet search = do
202216 result <- searchTweets search
203− let myTweet :: Either String Tweet
217+ let myTweet :: Either EsError Tweet
204218 myTweet = grabFirst result
205219 return myTweet
206220
207−searchTweets :: Search -> BH IO (Either String (SearchResult Tweet))
208−searchTweets search = eitherDecode . responseBody <$> searchByIndex testIndex search
221+searchTweets :: Search -> BH IO (Either EsError (SearchResult Tweet))
222+searchTweets search = parseEsResponse =<< searchByIndex testIndex search
209223
210224searchExpectNoResults :: Search -> BH IO ()
211225searchExpectNoResults search = do
@@ -239,19 +253,19 @@ searchTermsAggHint hints = do
239253 forM_ hints $ searchExpectAggs . search
240254 forM_ hints (\x -> searchValidBucketAgg (search x) "users" toTerms)
241255
242−searchTweetHighlight :: Search -> BH IO (Either String (Maybe HitHighlight))
256+searchTweetHighlight :: Search -> BH IO (Either EsError (Maybe HitHighlight))
243257searchTweetHighlight search = do
244258 result <- searchTweets search
245259 let myHighlight = fmap (hitHighlight . head . hits . searchHits) result
246260 return myHighlight
247261
248−searchExpectSource :: Source -> Either String Value -> BH IO ()
262+searchExpectSource :: Source -> Either EsError Value -> BH IO ()
249263searchExpectSource src expected = do
250264 _ <- insertData
251265 let query = QueryMatchQuery $ mkMatchQuery (FieldName "_all") (QueryString "haskell")
252266 let search = (mkSearch (Just query) Nothing) { source = Just src }
253267 reply <- searchAll search
254− let result = eitherDecode (responseBody reply) :: Either String (SearchResult Value)
268+ result <- parseEsResponse reply-- :: Either EsError (SearchResult Value)
255269 let value = grabFirst result
256270 liftIO $
257271 value `shouldBe` expected
@@ -265,42 +279,12 @@ instance ToJSON BulkTest where
265279noDuplicates :: Eq a => [a] -> Bool
266280noDuplicates xs = nub xs == xs
267281
268−instance Arbitrary RegexpFlags where
269− arbitrary = oneof [ pure AllRegexpFlags
270− , pure NoRegexpFlags
271− , SomeRegexpFlags <$> arbitrary
272− ]
273−
274282instance Arbitrary a => Arbitrary (NonEmpty a) where
275283 arbitrary = liftA2 (:|) arbitrary arbitrary
276284
277−instance Arbitrary RegexpFlag where
278− arbitrary = oneof [ pure AnyString
279− , pure Automaton
280− , pure Complement
281− , pure Empty
282− , pure Intersection
283− , pure Interval
284− ]
285−
286285arbitraryScore :: Gen Score
287286arbitraryScore = fmap getPositive <$> arbitrary
288287
289−instance Arbitrary Text where
290− arbitrary = T.pack <$> arbitrary
291−
292−instance (Arbitrary k, Arbitrary v, Ord k) => Arbitrary (M.Map k v) where
293− arbitrary = M.fromList <$> arbitrary
294−
295−instance Arbitrary IndexName where
296− arbitrary = IndexName <$> arbitrary
297−
298−instance Arbitrary MappingName where
299− arbitrary = MappingName <$> arbitrary
300−
301−instance Arbitrary DocId where
302− arbitrary = DocId <$> arbitrary
303−
304288instance Arbitrary a => Arbitrary (Hit a) where
305289 arbitrary = Hit <$> arbitrary
306290 <*> arbitrary
@@ -311,22 +295,212 @@ instance Arbitrary a => Arbitrary (Hit a) where
311295
312296
313297instance Arbitrary a => Arbitrary (SearchHits a) where
314− arbitrary = sized $ \n -> resize (n `div` 2) $ do
298+ arbitrary = reduceSize $ do
315299 tot <- getPositive <$> arbitrary
316300 score <- arbitraryScore
317301 hs <- arbitrary
318302 return $ SearchHits tot score hs
319303
304+reduceSize :: Gen a -> Gen a
305+reduceSize f = sized $ \n -> resize (n `div` 2) f
306+
320307getSource :: EsResult a -> Maybe a
321308getSource = fmap _source . foundResult
322309
323−grabFirst :: Either String (SearchResult a) -> Either String a
310+grabFirst :: Either EsError (SearchResult a) -> Either EsError a
324311grabFirst r =
325312 case fmap (hitSource . head . hits . searchHits) r of
326313 (Left e) -> Left e
327− (Right Nothing) -> Left "Source was missing"
314+ (Right Nothing) -> Left (EsError 500 "Source was missing")
328315 (Right (Just x)) -> Right x
329316
317+-------------------------------------------------------------------------------
318+arbitraryAlphaNum :: Gen Char
319+arbitraryAlphaNum = oneof [choose ('a', 'z')
320+ ,choose ('A','Z')
321+ , choose ('0', '9')]
322+
323+instance Arbitrary RoutingValue where
324+ arbitrary = RoutingValue . T.pack <$> listOf1 arbitraryAlphaNum
325+
326+instance Arbitrary AliasRouting where
327+ arbitrary = oneof [allAlias
328+ ,one
329+ ,theOther
330+ ,both]
331+ where one = GranularAliasRouting
332+ <$> (Just <$> arbitrary)
333+ <*> pure Nothing
334+ theOther = GranularAliasRouting Nothing
335+ <$> (Just <$> arbitrary)
336+ both = GranularAliasRouting
337+ <$> (Just <$> arbitrary)
338+ <*> (Just <$> arbitrary)
339+ allAlias = AllAliasRouting <$> arbitrary
340+
341+instance Arbitrary FieldName where
342+ arbitrary = FieldName . T.pack <$> listOf1 arbitraryAlphaNum
343+
344+instance Arbitrary RegexpFlags where
345+ arbitrary = oneof [ pure AllRegexpFlags
346+ , pure NoRegexpFlags
347+ , SomeRegexpFlags <$> genUniqueFlags
348+ ]
349+ where genUniqueFlags = NE.fromList . nub <$> listOf1 arbitrary
350+
351+instance Arbitrary IndexAliasCreate where
352+ arbitrary = IndexAliasCreate <$> arbitrary <*> reduceSize arbitrary
353+
354+instance Arbitrary Query where
355+ arbitrary = reduceSize $ oneof [ TermQuery <$> arbitrary <*> arbitrary
356+ , TermsQuery <$> arbitrary <*> arbitrary
357+ , QueryMatchQuery <$> arbitrary
358+ , QueryMultiMatchQuery <$> arbitrary
359+ , QueryBoolQuery <$> arbitrary
360+ , QueryBoostingQuery <$> arbitrary
361+ , QueryCommonTermsQuery <$> arbitrary
362+ , ConstantScoreFilter <$> arbitrary <*> arbitrary
363+ , ConstantScoreQuery <$> arbitrary <*> arbitrary
364+ , QueryDisMaxQuery <$> arbitrary
365+ , QueryFilteredQuery <$> arbitrary
366+ , QueryFuzzyLikeThisQuery <$> arbitrary
367+ , QueryFuzzyLikeFieldQuery <$> arbitrary
368+ , QueryFuzzyQuery <$> arbitrary
369+ , QueryHasChildQuery <$> arbitrary
370+ , QueryHasParentQuery <$> arbitrary
371+ , IdsQuery <$> arbitrary <*> arbitrary
372+ , QueryIndicesQuery <$> arbitrary
373+ , MatchAllQuery <$> arbitrary
374+ , QueryMoreLikeThisQuery <$> arbitrary
375+ , QueryMoreLikeThisFieldQuery <$> arbitrary
376+ , QueryNestedQuery <$> arbitrary
377+ , QueryPrefixQuery <$> arbitrary
378+ , QueryQueryStringQuery <$> arbitrary
379+ , QuerySimpleQueryStringQuery <$> arbitrary
380+ , QueryRangeQuery <$> arbitrary
381+ , QueryRegexpQuery <$> arbitrary
382+ ]
383+
384+instance Arbitrary Filter where
385+ arbitrary = reduceSize $ oneof [ AndFilter <$> arbitrary <*> arbitrary
386+ , OrFilter <$> arbitrary <*> arbitrary
387+ , NotFilter <$> arbitrary <*> arbitrary
388+ , pure IdentityFilter
389+ , BoolFilter <$> arbitrary
390+ , ExistsFilter <$> arbitrary
391+ , GeoBoundingBoxFilter <$> arbitrary
392+ , GeoDistanceFilter <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
393+ , GeoDistanceRangeFilter <$> arbitrary <*> arbitrary
394+ , GeoPolygonFilter <$> arbitrary <*> arbitrary
395+ , IdsFilter <$> arbitrary <*> arbitrary
396+ , LimitFilter <$> arbitrary
397+ , MissingFilter <$> arbitrary <*> arbitrary <*> arbitrary
398+ , PrefixFilter <$> arbitrary <*> arbitrary <*> arbitrary
399+ , QueryFilter <$> arbitrary <*> arbitrary
400+ , RangeFilter <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
401+ , RegexpFilter <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
402+ , TermFilter <$> arbitrary <*> arbitrary]
403+
404+$(derive makeArbitrary ''IndexName)
405+$(derive makeArbitrary ''MappingName)
406+$(derive makeArbitrary ''DocId)
407+$(derive makeArbitrary ''Version)
408+$(derive makeArbitrary ''IndexAliasRouting)
409+$(derive makeArbitrary ''ShardCount)
410+$(derive makeArbitrary ''ReplicaCount)
411+$(derive makeArbitrary ''TemplateName)
412+$(derive makeArbitrary ''TemplatePattern)
413+$(derive makeArbitrary ''QueryString)
414+$(derive makeArbitrary ''CacheName)
415+$(derive makeArbitrary ''CacheKey)
416+$(derive makeArbitrary ''Existence)
417+$(derive makeArbitrary ''CutoffFrequency)
418+$(derive makeArbitrary ''Analyzer)
419+$(derive makeArbitrary ''MaxExpansions)
420+$(derive makeArbitrary ''Lenient)
421+$(derive makeArbitrary ''Tiebreaker)
422+$(derive makeArbitrary ''Boost)
423+$(derive makeArbitrary ''BoostTerms)
424+$(derive makeArbitrary ''MinimumMatch)
425+$(derive makeArbitrary ''DisableCoord)
426+$(derive makeArbitrary ''IgnoreTermFrequency)
427+$(derive makeArbitrary ''MinimumTermFrequency)
428+$(derive makeArbitrary ''MaxQueryTerms)
429+$(derive makeArbitrary ''Fuzziness)
430+$(derive makeArbitrary ''PrefixLength)
431+$(derive makeArbitrary ''TypeName)
432+$(derive makeArbitrary ''PercentMatch)
433+$(derive makeArbitrary ''StopWord)
434+$(derive makeArbitrary ''QueryPath)
435+$(derive makeArbitrary ''AllowLeadingWildcard)
436+$(derive makeArbitrary ''LowercaseExpanded)
437+$(derive makeArbitrary ''EnablePositionIncrements)
438+$(derive makeArbitrary ''AnalyzeWildcard)
439+$(derive makeArbitrary ''GeneratePhraseQueries)
440+$(derive makeArbitrary ''Locale)
441+$(derive makeArbitrary ''MaxWordLength)
442+$(derive makeArbitrary ''MinWordLength)
443+$(derive makeArbitrary ''PhraseSlop)
444+$(derive makeArbitrary ''MinDocFrequency)
445+$(derive makeArbitrary ''MaxDocFrequency)
446+$(derive makeArbitrary ''Regexp)
447+$(derive makeArbitrary ''SimpleQueryStringQuery)
448+$(derive makeArbitrary ''FieldOrFields)
449+$(derive makeArbitrary ''SimpleQueryFlag)
450+$(derive makeArbitrary ''RegexpQuery)
451+$(derive makeArbitrary ''QueryStringQuery)
452+$(derive makeArbitrary ''RangeQuery)
453+$(derive makeArbitrary ''RangeValue)
454+$(derive makeArbitrary ''PrefixQuery)
455+$(derive makeArbitrary ''NestedQuery)
456+$(derive makeArbitrary ''MoreLikeThisFieldQuery)
457+$(derive makeArbitrary ''MoreLikeThisQuery)
458+$(derive makeArbitrary ''IndicesQuery)
459+$(derive makeArbitrary ''HasParentQuery)
460+$(derive makeArbitrary ''HasChildQuery)
461+$(derive makeArbitrary ''FuzzyQuery)
462+$(derive makeArbitrary ''FuzzyLikeFieldQuery)
463+$(derive makeArbitrary ''FuzzyLikeThisQuery)
464+$(derive makeArbitrary ''FilteredQuery)
465+$(derive makeArbitrary ''DisMaxQuery)
466+$(derive makeArbitrary ''CommonTermsQuery)
467+$(derive makeArbitrary ''DistanceRange)
468+$(derive makeArbitrary ''MultiMatchQuery)
469+$(derive makeArbitrary ''LessThanD)
470+$(derive makeArbitrary ''LessThanEqD)
471+$(derive makeArbitrary ''GreaterThanD)
472+$(derive makeArbitrary ''GreaterThanEqD)
473+$(derive makeArbitrary ''LessThan)
474+$(derive makeArbitrary ''LessThanEq)
475+$(derive makeArbitrary ''GreaterThan)
476+$(derive makeArbitrary ''GreaterThanEq)
477+$(derive makeArbitrary ''GeoPoint)
478+$(derive makeArbitrary ''NullValue)
479+$(derive makeArbitrary ''MinimumMatchHighLow)
480+$(derive makeArbitrary ''CommonMinimumMatch)
481+$(derive makeArbitrary ''BoostingQuery)
482+$(derive makeArbitrary ''BoolQuery)
483+$(derive makeArbitrary ''MatchQuery)
484+$(derive makeArbitrary ''MultiMatchQueryType)
485+$(derive makeArbitrary ''BooleanOperator)
486+$(derive makeArbitrary ''ZeroTermsQuery)
487+$(derive makeArbitrary ''MatchQueryType)
488+$(derive makeArbitrary ''SearchAliasRouting)
489+$(derive makeArbitrary ''ScoreType)
490+$(derive makeArbitrary ''Distance)
491+$(derive makeArbitrary ''DistanceUnit)
492+$(derive makeArbitrary ''DistanceType)
493+$(derive makeArbitrary ''OptimizeBbox)
494+$(derive makeArbitrary ''GeoBoundingBoxConstraint)
495+$(derive makeArbitrary ''GeoFilterType)
496+$(derive makeArbitrary ''GeoBoundingBox)
497+$(derive makeArbitrary ''LatLon)
498+$(derive makeArbitrary ''RangeExecution)
499+$(derive makeArbitrary ''RegexpFlag)
500+$(derive makeArbitrary ''BoolMatch)
501+$(derive makeArbitrary ''Term)
502+
503+
330504main :: IO ()
331505main = hspec $ do
332506
@@ -437,9 +611,29 @@ main = hspec $ do
437611 liftIO $
438612 myTweet `shouldBe` Right exampleTweet
439613
614+ it "handles constant score queries" $ withTestEnv $ do
615+ _ <- insertData
616+ let query = TermsQuery "user" ("bitemyapp" :| [])
617+ let cfQuery = ConstantScoreQuery query (Boost 1.0)
618+ let filter = IdentityFilter
619+ let search = mkSearch (Just cfQuery) (Just filter)
620+ myTweet <- searchTweet search
621+ liftIO $
622+ myTweet `shouldBe` Right exampleTweet
623+ it "handles constant score filters" $ withTestEnv $ do
624+ _ <- insertData
625+ let query = TermsQuery "user" ("bitemyapp" :| [])
626+ let cfFilter = ConstantScoreFilter IdentityFilter (Boost 1.0)
627+ let boolQuery = mkBoolQuery [query, cfFilter] [] []
628+ let search = mkSearch (Just (QueryBoolQuery boolQuery)) Nothing
629+ myTweet <- searchTweet search
630+ liftIO $
631+ myTweet `shouldBe` Right exampleTweet
632+
633+
440634 it "returns document for terms query and identity filter" $ withTestEnv $ do
441635 _ <- insertData
442− let query = TermsQuery (NE.fromList [(Term "user" "bitemyapp")])
636+ let query = TermsQuery "user" ("bitemyapp" :| [])
443637 let filter = IdentityFilter <&&> IdentityFilter
444638 let search = mkSearch (Just query) (Just filter)
445639 myTweet <- searchTweet search
@@ -772,7 +966,7 @@ main = hspec $ do
772966 it "doesn't include source when sources are disabled" $ withTestEnv $ do
773967 searchExpectSource
774968 NoSource
775− (Left "Source was missing")
969+ (Left (EsError 500 "Source was missing"))
776970
777971 it "includes a source" $ withTestEnv $ do
778972 searchExpectSource
@@ -869,3 +1063,139 @@ main = hspec $ do
8691063 regular_search `shouldBe` Right exampleTweet -- Check that the size restrtiction is being honored
8701064 liftIO $
8711065 scan_search `shouldMatchList` [Just exampleTweet, Just otherTweet]
1066+
1067+ describe "index aliases" $ do
1068+ it "handles the simple case of aliasing an existing index" $ do
1069+ let alias = IndexAlias (testIndex) (IndexAliasName (IndexName "bloodhound-tests-twitter-1-alias"))
1070+ let create = IndexAliasCreate Nothing Nothing
1071+ let action = AddAlias alias create
1072+
1073+ withTestEnv $ do
1074+ resetIndex
1075+ resp <- updateIndexAliases (action :| [])
1076+ liftIO $ NHTS.statusCode (responseStatus resp) `shouldBe` 200
1077+ let cleanup = withTestEnv (updateIndexAliases (RemoveAlias alias :| []))
1078+ (do aliases <- withTestEnv getIndexAliases
1079+ let expected = IndexAliasSummary alias create
1080+ case aliases of
1081+ Right (IndexAliasesSummary summs) ->
1082+ L.find ((== alias) . indexAliasSummaryAlias) summs `shouldBe` Just expected
1083+ Left e -> expectationFailure ("Expected an IndexAliasesSummary but got " <> show e)) `finally` cleanup
1084+
1085+ it "handles an alias with routing and a filter" $ do
1086+ let alias = IndexAlias (testIndex) (IndexAliasName (IndexName "bloodhound-tests-twitter-1-alias"))
1087+ let sar = SearchAliasRouting (RoutingValue "search val" :| [])
1088+ let iar = IndexAliasRouting (RoutingValue "index val")
1089+ let routing = GranularAliasRouting (Just sar) (Just iar)
1090+ let filter = LimitFilter 42
1091+ let create = IndexAliasCreate (Just routing) (Just filter)
1092+ let action = AddAlias alias create
1093+
1094+ withTestEnv $ do
1095+ resetIndex
1096+ resp <- updateIndexAliases (action :| [])
1097+ liftIO $ NHTS.statusCode (responseStatus resp) `shouldBe` 200
1098+ let cleanup = withTestEnv (updateIndexAliases (RemoveAlias alias :| []))
1099+ (do aliases <- withTestEnv getIndexAliases
1100+ let expected = IndexAliasSummary alias create
1101+ case aliases of
1102+ Right (IndexAliasesSummary summs) ->
1103+ L.find ((== alias) . indexAliasSummaryAlias) summs `shouldBe` Just expected
1104+ Left e -> expectationFailure ("Expected an IndexAliasesSummary but got " <> show e)) `finally` cleanup
1105+
1106+ describe "JSON instances" $ do
1107+ propJSON (Proxy :: Proxy Version)
1108+ propJSON (Proxy :: Proxy IndexName)
1109+ propJSON (Proxy :: Proxy MappingName)
1110+ propJSON (Proxy :: Proxy DocId)
1111+ propJSON (Proxy :: Proxy IndexAliasRouting)
1112+ propJSON (Proxy :: Proxy RoutingValue)
1113+ propJSON (Proxy :: Proxy ShardCount)
1114+ propJSON (Proxy :: Proxy ReplicaCount)
1115+ propJSON (Proxy :: Proxy TemplateName)
1116+ propJSON (Proxy :: Proxy TemplatePattern)
1117+ propJSON (Proxy :: Proxy QueryString)
1118+ propJSON (Proxy :: Proxy FieldName)
1119+ propJSON (Proxy :: Proxy CacheName)
1120+ propJSON (Proxy :: Proxy CacheKey)
1121+ propJSON (Proxy :: Proxy Existence)
1122+ propJSON (Proxy :: Proxy CutoffFrequency)
1123+ propJSON (Proxy :: Proxy Analyzer)
1124+ propJSON (Proxy :: Proxy MaxExpansions)
1125+ propJSON (Proxy :: Proxy Lenient)
1126+ propJSON (Proxy :: Proxy Tiebreaker)
1127+ propJSON (Proxy :: Proxy Boost)
1128+ propJSON (Proxy :: Proxy BoostTerms)
1129+ propJSON (Proxy :: Proxy MaxExpansions)
1130+ propJSON (Proxy :: Proxy MinimumMatch)
1131+ propJSON (Proxy :: Proxy DisableCoord)
1132+ propJSON (Proxy :: Proxy IgnoreTermFrequency)
1133+ propJSON (Proxy :: Proxy MinimumTermFrequency)
1134+ propJSON (Proxy :: Proxy MaxQueryTerms)
1135+ propJSON (Proxy :: Proxy Fuzziness)
1136+ propJSON (Proxy :: Proxy PrefixLength)
1137+ propJSON (Proxy :: Proxy TypeName)
1138+ propJSON (Proxy :: Proxy PercentMatch)
1139+ propJSON (Proxy :: Proxy StopWord)
1140+ propJSON (Proxy :: Proxy QueryPath)
1141+ propJSON (Proxy :: Proxy AllowLeadingWildcard)
1142+ propJSON (Proxy :: Proxy LowercaseExpanded)
1143+ propJSON (Proxy :: Proxy EnablePositionIncrements)
1144+ propJSON (Proxy :: Proxy AnalyzeWildcard)
1145+ propJSON (Proxy :: Proxy GeneratePhraseQueries)
1146+ propJSON (Proxy :: Proxy Locale)
1147+ propJSON (Proxy :: Proxy MaxWordLength)
1148+ propJSON (Proxy :: Proxy MinWordLength)
1149+ propJSON (Proxy :: Proxy PhraseSlop)
1150+ propJSON (Proxy :: Proxy MinDocFrequency)
1151+ propJSON (Proxy :: Proxy MaxDocFrequency)
1152+ propJSON (Proxy :: Proxy Filter)
1153+ propJSON (Proxy :: Proxy Query)
1154+ propJSON (Proxy :: Proxy SimpleQueryStringQuery)
1155+ propJSON (Proxy :: Proxy FieldOrFields)
1156+ propJSON (Proxy :: Proxy SimpleQueryFlag)
1157+ propJSON (Proxy :: Proxy RegexpQuery)
1158+ propJSON (Proxy :: Proxy QueryStringQuery)
1159+ propJSON (Proxy :: Proxy RangeQuery)
1160+ propJSON (Proxy :: Proxy PrefixQuery)
1161+ propJSON (Proxy :: Proxy NestedQuery)
1162+ propJSON (Proxy :: Proxy MoreLikeThisFieldQuery)
1163+ propJSON (Proxy :: Proxy MoreLikeThisQuery)
1164+ propJSON (Proxy :: Proxy IndicesQuery)
1165+ propJSON (Proxy :: Proxy HasParentQuery)
1166+ propJSON (Proxy :: Proxy HasChildQuery)
1167+ propJSON (Proxy :: Proxy FuzzyQuery)
1168+ propJSON (Proxy :: Proxy FuzzyLikeFieldQuery)
1169+ propJSON (Proxy :: Proxy FuzzyLikeThisQuery)
1170+ propJSON (Proxy :: Proxy FilteredQuery)
1171+ propJSON (Proxy :: Proxy DisMaxQuery)
1172+ propJSON (Proxy :: Proxy CommonTermsQuery)
1173+ propJSON (Proxy :: Proxy CommonMinimumMatch)
1174+ propJSON (Proxy :: Proxy BoostingQuery)
1175+ propJSON (Proxy :: Proxy BoolQuery)
1176+ propJSON (Proxy :: Proxy MatchQuery)
1177+ propJSON (Proxy :: Proxy MultiMatchQueryType)
1178+ propJSON (Proxy :: Proxy BooleanOperator)
1179+ propJSON (Proxy :: Proxy ZeroTermsQuery)
1180+ propJSON (Proxy :: Proxy MatchQueryType)
1181+ propJSON (Proxy :: Proxy AliasRouting)
1182+ propJSON (Proxy :: Proxy IndexAliasCreate)
1183+ propJSON (Proxy :: Proxy SearchAliasRouting)
1184+ propJSON (Proxy :: Proxy ScoreType)
1185+ propJSON (Proxy :: Proxy Distance)
1186+ propJSON (Proxy :: Proxy DistanceUnit)
1187+ propJSON (Proxy :: Proxy DistanceType)
1188+ propJSON (Proxy :: Proxy OptimizeBbox)
1189+ propJSON (Proxy :: Proxy GeoBoundingBoxConstraint)
1190+ propJSON (Proxy :: Proxy GeoFilterType)
1191+ propJSON (Proxy :: Proxy GeoBoundingBox)
1192+ propJSON (Proxy :: Proxy LatLon)
1193+ propJSON (Proxy :: Proxy RangeExecution)
1194+ prop "RegexpFlags FromJSON/ToJSON roundtrips, removing dups " $ \rfs ->
1195+ let expected = case rfs of
1196+ SomeRegexpFlags fs -> SomeRegexpFlags (NE.fromList (nub (NE.toList fs)))
1197+ x -> x
1198+ in parseEither parseJSON (toJSON rfs) === Right expected
1199+ propJSON (Proxy :: Proxy BoolMatch)
1200+ propJSON (Proxy :: Proxy Term)
1201+ propJSON (Proxy :: Proxy MultiMatchQuery)