@@ -1,9 +1,6 @@
1−{-# LANGUAGE DeriveGeneric, ExistentialQuantification, StandaloneDeriving #-}
3module Database.Bloodhound.Client
1module Database.Bloodhound.Client
4 ( createIndex
2 ( createIndex
5 , deleteIndex
3 , deleteIndex
6− , defaultIndexSettings
7 , createMapping
4 , createMapping
8 , deleteMapping
5 , deleteMapping
9 , indexDocument
6 , indexDocument
@@ -16,95 +13,22 @@ module Database.Bloodhound.Client
16 , refreshIndex
13 , refreshIndex
17 , mkSearch
14 , mkSearch
34− , GeoBoundingBoxConstraint(..)
62−import Control.Applicative
63−import Control.Monad (liftM)
64import Data.Aeson
19import Data.Aeson
65−import Data.Aeson.TH (deriveJSON)
66import qualified Data.ByteString.Lazy.Char8 as L
20import qualified Data.ByteString.Lazy.Char8 as L
67import Data.ByteString.Builder
21import Data.ByteString.Builder
68import Data.List (foldl', intercalate, intersperse)
22import Data.List (foldl', intercalate, intersperse)
69import Data.Maybe (fromMaybe)
23import Data.Maybe (fromMaybe)
71import Data.Text (Text)
24import Data.Text (Text)
72−import qualified Data.Text as T
73−import Data.Time.Clock (UTCTime)
74−import GHC.Generics (Generic)
75import Network.HTTP.Conduit
25import Network.HTTP.Conduit
76import qualified Network.HTTP.Types.Method as NHTM
26import qualified Network.HTTP.Types.Method as NHTM
77import qualified Network.HTTP.Types.Status as NHTS
27import qualified Network.HTTP.Types.Status as NHTS
79−data Version = Version { number :: Text
29+import Database.Bloodhound.Types
80− , build_hash :: Text
30+import Database.Bloodhound.Types.Class
81− , build_timestamp :: UTCTime
31+import Database.Bloodhound.Types.Instances
82− , build_snapshot :: Bool
83− , lucene_version :: Text } deriving (Show, Generic)
85−data (FromJSON a, ToJSON a) => Status a =
90− , tagline :: Text } deriving (Eq, Show)
92−instance ToJSON Version
93−instance FromJSON Version
95−instance (FromJSON a, ToJSON a) => FromJSON (Status a) where
96− parseJSON (Object v) = Status <$>
104−main = simpleHttp "http://localhost:9200/events/event/_search?q=hostname:localhost&size=1" >>= L.putStrLn
106−newtype ShardCount = ShardCount Int deriving (Eq, Show, Generic)
107−newtype ReplicaCount = ReplicaCount Int deriving (Eq, Show, Generic)
109mkShardCount :: Int -> Maybe ShardCount
33mkShardCount :: Int -> Maybe ShardCount
110mkShardCount n
34mkShardCount n
@@ -118,25 +42,6 @@ mkReplicaCount n
118 | n > 1000 = Nothing -- ...
42 | n > 1000 = Nothing -- ...
119 | otherwise = Just (ReplicaCount n)
43 | otherwise = Just (ReplicaCount n)
122− IndexSettings { indexShards :: ShardCount
123− , indexReplicas :: ReplicaCount } deriving (Eq, Show)
125−instance ToJSON IndexSettings where
126− toJSON (IndexSettings s r) = object ["settings" .= object ["shards" .= s, "replicas" .= r]]
128−instance ToJSON ReplicaCount
129−instance ToJSON ShardCount
131−defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
133−data Strategy = RoundRobinStrat | RandomStrat | HeadStrat deriving (Eq, Show)
135−newtype Server = Server String deriving (Eq, Show)
137−type Reply = Network.HTTP.Conduit.Response L.ByteString
138−type Method = NHTM.Method
140responseIsError :: Reply -> Bool
45responseIsError :: Reply -> Bool
141responseIsError resp = NHTS.statusCode (responseStatus resp) > 299
46responseIsError resp = NHTS.statusCode (responseStatus resp) > 299
@@ -194,8 +99,6 @@ refreshIndex (Server server) (IndexName indexName) = dispatch url method body wh
194 method = NHTM.methodPost
99 method = NHTM.methodPost
195 body = Nothing
100 body = Nothing
197−data OpenCloseIndex = OpenIndex | CloseIndex deriving (Eq, Show)
199stringifyOCIndex oci = case oci of
102stringifyOCIndex oci = case oci of
200 OpenIndex -> "_open"
103 OpenIndex -> "_open"
201 CloseIndex -> "_close"
104 CloseIndex -> "_close"
@@ -214,24 +117,6 @@ openIndex = openOrCloseIndexes OpenIndex
214closeIndex :: Server -> IndexName -> IO Reply
117closeIndex :: Server -> IndexName -> IO Reply
215closeIndex = openOrCloseIndexes CloseIndex
118closeIndex = openOrCloseIndexes CloseIndex
217−data FieldType = GeoPointType
223− | ByteType deriving (Eq, Show)
225−data FieldDefinition =
226− FieldDefinition { fieldType :: FieldType } deriving (Eq, Show)
229− MappingField { mappingFieldName :: FieldName
230− , fieldDefinition :: FieldDefinition } deriving (Eq, Show)
232−data Mapping = Mapping { typeName :: Text
233− , fields :: [MappingField] } deriving (Eq, Show)
235createMapping :: ToJSON a => Server -> IndexName
120createMapping :: ToJSON a => Server -> IndexName
236 -> MappingName -> a -> IO Reply
121 -> MappingName -> a -> IO Reply
237createMapping (Server server) (IndexName indexName) (MappingName mappingName) mapping =
122createMapping (Server server) (IndexName indexName) (MappingName mappingName) mapping =
@@ -280,12 +165,6 @@ collapseStream stream = collapsed where
280mash :: Builder -> [L.ByteString] -> Builder
165mash :: Builder -> [L.ByteString] -> Builder
281mash builder xs = foldl' (\b x -> mappend b (lazyByteString x)) builder xs
166mash builder xs = foldl' (\b x -> mappend b (lazyByteString x)) builder xs
284− BulkIndex IndexName MappingName DocId Value
285− | BulkCreate IndexName MappingName DocId Value
286− | BulkDelete IndexName MappingName DocId
287− | BulkUpdate IndexName MappingName DocId Value deriving (Eq, Show)
289mkMetadataValue :: Text -> String -> String -> String -> Value
168mkMetadataValue :: Text -> String -> String -> String -> Value
290mkMetadataValue operation indexName mappingName docId =
169mkMetadataValue operation indexName mappingName docId =
291 object [operation .=
170 object [operation .=
@@ -319,23 +198,6 @@ getStreamChunk (BulkUpdate (IndexName indexName)
319 doc = object ["doc" .= value]
198 doc = object ["doc" .= value]
320 blob = [encode metadata, encode doc]
199 blob = [encode metadata, encode doc]
322−data EsResult a = EsResult { _index :: Text
326− , found :: Maybe Bool
327− , _source :: a } deriving (Eq, Show)
329−instance (FromJSON a, ToJSON a) => FromJSON (EsResult a) where
330− parseJSON (Object v) = EsResult <$>
339getDocument :: Server -> IndexName -> MappingName
201getDocument :: Server -> IndexName -> MappingName
340 -> DocId -> IO Reply
202 -> DocId -> IO Reply
341getDocument (Server server) (IndexName indexName) (MappingName mappingName) (DocId docId) =
203getDocument (Server server) (IndexName indexName) (MappingName mappingName) (DocId docId) =
@@ -351,7 +213,6 @@ documentExists (Server server) (IndexName indexName) (MappingName mappingName) (
351 return exists where
213 return exists where
352 url = joinPath [server, indexName, mappingName, docId]
214 url = joinPath [server, indexName, mappingName, docId]
355dispatchSearch :: String -> Search -> IO Reply
216dispatchSearch :: String -> Search -> IO Reply
356dispatchSearch url search = dispatch url NHTM.methodPost (Just (encode search))
217dispatchSearch url search = dispatch url NHTM.methodPost (Just (encode search))
@@ -368,557 +229,8 @@ searchByType (Server server) (IndexName indexName)
368 (MappingName mappingName) search = dispatchSearch url search where
229 (MappingName mappingName) search = dispatchSearch url search where
369 url = joinPath [server, indexName, mappingName, "_search"]
230 url = joinPath [server, indexName, mappingName, "_search"]
371−data Search = Search { queryBody :: Maybe Query
372− , filterBody :: Maybe Filter
373− , sortBody :: Maybe Sort
375− , trackSortScores :: Bool
377− , size :: Int} deriving (Eq, Show)
379mkSearch :: Maybe Query -> Maybe Filter -> Search
232mkSearch :: Maybe Query -> Maybe Filter -> Search
380mkSearch query filter = Search query filter Nothing False 0 10
233mkSearch query filter = Search query filter Nothing False 0 10
382pageSearch :: Int -> Int -> Search -> Search
235pageSearch :: Int -> Int -> Search -> Search
383pageSearch from size search = search { from = from, size = size }
236pageSearch from size search = search { from = from, size = size }
385−-- defaultFieldMaybeJSON :: Text -> Maybe a ->
386−maybeJson field (Just value) = [field .= toJSON value]
388−maybeJsonF field (Just value) = [field .= fmap toJSON value]
391−instance ToJSON Search where
392− toJSON (Search query filter sort trackSortScores from size) =
394− lQuery = maybeJson "query" query
395− lFilter = maybeJson "filter" filter
396− lSort = maybeJsonF "sort" sort
397− merged = mconcat [[ "from" .= from
399− , "track_scores" .= trackSortScores]
404−type Sort = [SortSpec]
406−data SortSpec = DefaultSortSpec DefaultSort
407− | GeoDistanceSortSpec SortOrder GeoPoint deriving (Eq, Show)
409−instance ToJSON SortSpec where
410− toJSON (DefaultSortSpec
411− (DefaultSort (FieldName sortFieldName) sortOrder ignoreUnmapped
412− sortMode missingSort nestedFilter)) =
413− object [sortFieldName .= object merged] where
414− base = ["order" .= toJSON sortOrder
415− , "ignore_unmapped" .= ignoreUnmapped]
416− lSortMode = maybeJson "mode" sortMode
417− lMissingSort = maybeJson "missing" missingSort
418− lNestedFilter = maybeJson "nested_filter" nestedFilter
419− merged = mconcat [base, lSortMode, lMissingSort, lNestedFilter]
421−instance ToJSON SortOrder where
422− toJSON Ascending = String "asc"
423− toJSON Descending = String "desc"
425−instance ToJSON SortMode where
426− toJSON SortMin = String "min"
427− toJSON SortMax = String "max"
428− toJSON SortSum = String "sum"
429− toJSON SortAvg = String "avg"
431−instance ToJSON Missing where
432− toJSON LastMissing = String "_last"
433− toJSON FirstMissing = String "_first"
434− toJSON (CustomMissing txt) = String txt
437− DefaultSort { sortFieldName :: FieldName
438− , sortOrder :: SortOrder
440− , ignoreUnmapped :: Bool
441− , sortMode :: Maybe SortMode
442− , missingSort :: Maybe Missing
443− , nestedFilter :: Maybe Filter } deriving (Eq, Show)
445−data SortOrder = Ascending
446− | Descending deriving (Eq, Show)
448−data Missing = LastMissing
450− | CustomMissing Text deriving (Eq, Show)
452−data SortMode = SortMin
455− | SortAvg deriving (Eq, Show)
458−-- author:"John Smith"
459−-- for book.title and book.date containing quick OR brown, book.\*:(quick brown)
460−-- field title has no value or doesn't exist, _missing_:title
461−-- field title has any non-null value, _exists:title
463−-- type DisMax = Bool -- "use_dis_max"
464−-- newtype TieBreaker = TieBreaker Int deriving (Eq, Show)
465−-- data QueryField = DefaultField Text
466−-- | Fields [Text] DisMax TieBreaker deriving (Eq, Show)
468−-- -- this is will go away later
470−-- data QueryStringQuery =
471−-- QueryStringQuery { query :: Text
473−-- , field :: Maybe QueryField
475−-- , defaultOperator :: Maybe BooleanOperator
477−-- , analyzer :: Maybe Text
479−-- , allowLeadingWildcard :: Maybe Bool
481−-- , lowercaseExpandedTerms :: Maybe Bool
483−-- , enablePositionIncrements :: Maybe Bool
485−-- , fuzzyMaxExpansions :: Maybe Int
486−-- -- Fuzziness -- default AUTO, add type later
487−-- , fuzziness :: Maybe Text
488−-- , fuzzyPrefixLength :: Maybe Int -- default 0
489−-- -- default 0, 0 means exact phrase matches
490−-- , phraseSlop :: Maybe Int
492−-- , boost :: Maybe Double
493−-- -- default false, true forces wildcard analysis
494−-- , analyzeWildcard :: Maybe Bool
496−-- , autoGeneratePhraseQueries :: Maybe Bool
497−-- -- # "should" clauses in the boolean query should match
498−-- , minimumShouldMatch :: Maybe Text
499−-- -- Text to handle weird % and other cases. Needs type
500−-- -- default false, true shuts off format based failures
501−-- , lenient :: Maybe Bool
502−-- -- default ROOT, locale used for string conversions
503−-- , locale :: Maybe Text
504−-- } deriving (Eq, Show)
506−-- emptyQueryStringQuery = QueryStringQuery "" Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
507−-- queryStringQuery query = emptyQueryStringQuery { query = query }
509−-- type FieldName = Text
511−type Cache = Bool -- caching on/off
514−type PrefixValue = Text
516−data BooleanOperator = And | Or deriving (Eq, Show)
518−newtype IndexName = IndexName String deriving (Eq, Generic, Show)
519−newtype MappingName = MappingName String deriving (Eq, Generic, Show)
520−newtype DocId = DocId String deriving (Eq, Generic, Show)
521−newtype QueryString = QueryString Text deriving (Eq, Show)
522−newtype FieldName = FieldName Text deriving (Eq, Show)
523−newtype CacheName = CacheName Text deriving (Eq, Show)
524−newtype CacheKey = CacheKey Text deriving (Eq, Show)
525−newtype Existence = Existence Bool deriving (Eq, Show)
526−newtype NullValue = NullValue Bool deriving (Eq, Show)
528−unpackId :: DocId -> String
529−unpackId (DocId docId) = docId
531−instance FromJSON IndexName
532−instance FromJSON MappingName
533−instance FromJSON DocId
535−-- data QueryType = BooleanQueryType
537−-- | PhrasePrefixQueryType deriving (Eq, Show)
540−data Query = TermQuery Term (Maybe Boost)
541− | ConstantScoreFilter Filter Boost
542− | ConstantScoreQuery Query Boost
545−instance ToJSON Query where
546− toJSON (TermQuery (Term termField termValue) boost) =
548− object [termField .= object merged]]
550− base = ["value" .= termValue]
551− boosted = case boost of
552− (Just boostValue) -> ["boost" .= boostValue]
554− merged = mappend base boosted
556−data Filter = AndFilter [Filter] Cache
557− | OrFilter [Filter] Cache
558− | NotFilter Filter Cache
560− | BoolFilter BoolMatch
561− | ExistsFilter FieldName -- always cached
562− | GeoBoundingBoxFilter GeoBoundingBoxConstraint GeoFilterType
563− | GeoDistanceFilter GeoPoint Distance DistanceType OptimizeBbox Cache
564− | GeoDistanceRangeFilter GeoPoint DistanceRange
565− | GeoPolygonFilter FieldName [LatLon]
566− | IdsFilter MappingName [DocId]
568− | MissingFilter FieldName Existence NullValue
569− | PrefixFilter FieldName PrefixValue Cache
570− | RangeFilter FieldName (Either HalfRange Range) RangeExecution Cache
571− | RegexpFilter FieldName Regexp RegexpFlags CacheName Cache CacheKey
574−class Monoid a => Seminearring a where
576− (<||>) :: a -> a -> a
577− (<&&>) :: a -> a -> a
583−instance Monoid Filter where
584− mempty = IdentityFilter
585− mappend a b = AndFilter [a, b] defaultCache
587−instance Seminearring Filter where
588− a <||> b = OrFilter [a, b] defaultCache
590−instance ToJSON Filter where
591− toJSON (AndFilter filters cache) =
592− object ["and" .= fmap toJSON filters
593− , "_cache" .= cache]
595− toJSON (OrFilter filters cache) =
596− object ["or" .= fmap toJSON filters
597− , "_cache" .= cache]
599− toJSON (NotFilter filter cache) =
601− object ["filter" .= toJSON filter
602− , "_cache" .= cache]]
604− toJSON (IdentityFilter) =
605− object ["match_all" .= object []]
607− toJSON (ExistsFilter (FieldName fieldName)) =
608− object ["exists" .= object
609− ["field" .= fieldName]]
611− toJSON (BoolFilter boolMatch) =
612− object ["bool" .= toJSON boolMatch]
614− toJSON (GeoBoundingBoxFilter bbConstraint filterType) =
615− object ["geo_bounding_box" .= toJSON bbConstraint
616− , "type" .= toJSON filterType]
618− toJSON (GeoDistanceFilter (GeoPoint (FieldName geoField) latLon)
619− distance distanceType optimizeBbox cache) =
620− object ["geo_distance" .=
621− object ["distance" .= toJSON distance
622− , "distance_type" .= toJSON distanceType
623− , "optimize_bbox" .= optimizeBbox
624− , geoField .= toJSON latLon
625− , "_cache" .= cache]]
627− toJSON (GeoDistanceRangeFilter (GeoPoint (FieldName geoField) latLon)
628− (DistanceRange distanceFrom distanceTo)) =
629− object ["geo_distance_range" .=
630− object ["from" .= toJSON distanceFrom
631− , "to" .= toJSON distanceTo
632− , geoField .= toJSON latLon]]
634− toJSON (GeoPolygonFilter (FieldName geoField) latLons) =
635− object ["geo_polygon" .=
637− object ["points" .= fmap toJSON latLons]]]
639− toJSON (IdsFilter (MappingName mappingName) values) =
641− object ["type" .= mappingName
642− , "values" .= fmap (T.pack . unpackId) values]]
644− toJSON (LimitFilter limit) =
645− object ["limit" .= object ["value" .= limit]]
647− toJSON (MissingFilter (FieldName fieldName) (Existence existence) (NullValue nullValue)) =
648− object ["missing" .=
649− object ["field" .= fieldName
650− , "existence" .= existence
651− , "null_value" .= nullValue]]
653− toJSON (PrefixFilter (FieldName fieldName) fieldValue cache) =
655− object [fieldName .= fieldValue
656− , "_cache" .= cache]]
658− toJSON (RangeFilter (FieldName fieldName) (Left halfRange) rangeExecution cache) =
660− object [fieldName .=
662− , "execution" .= toJSON rangeExecution
663− , "_cache" .= cache]]
665− (key, val) = halfRangeToKV halfRange
667− toJSON (RangeFilter (FieldName fieldName) (Right range) rangeExecution cache) =
669− object [fieldName .=
670− object [lessKey .= lessVal
671− , greaterKey .= greaterVal]
672− , "execution" .= toJSON rangeExecution
673− , "_cache" .= cache]]
675− (lessKey, lessVal, greaterKey, greaterVal) = rangeToKV range
677− toJSON (RegexpFilter (FieldName fieldName)
678− (Regexp regexText) flags (CacheName cacheName) cache (CacheKey cacheKey)) =
680− object [fieldName .=
681− object ["value" .= regexText
682− , "flags" .= toJSON flags]
683− , "_name" .= cacheName
685− , "_cache_key" .= cacheKey]]
687−instance ToJSON GeoPoint where
688− toJSON (GeoPoint (FieldName geoField) latLon) =
689− object [geoField .= toJSON latLon]
691−showText :: Show a => a -> Text
692−showText = T.pack . show
694−instance ToJSON Distance where
695− toJSON (Distance coefficient unit) =
696− String boltedTogether where
697− coefText = showText coefficient
698− (String unitText) = (toJSON unit)
699− boltedTogether = mappend coefText unitText
701−instance ToJSON DistanceUnit where
702− toJSON Miles = String "mi"
703− toJSON Yards = String "yd"
704− toJSON Feet = String "ft"
705− toJSON Inches = String "in"
706− toJSON Kilometers = String "km"
707− toJSON Meters = String "m"
708− toJSON Centimeters = String "cm"
709− toJSON Millimeters = String "mm"
710− toJSON NauticalMiles = String "nmi"
712−instance ToJSON DistanceType where
713− toJSON Arc = String "arc"
714− toJSON SloppyArc = String "sloppy_arc"
715− toJSON Plane = String "plane"
717−instance ToJSON OptimizeBbox where
718− toJSON NoOptimizeBbox = String "none"
719− toJSON (OptimizeGeoFilterType gft) = toJSON gft
721−instance ToJSON GeoBoundingBoxConstraint where
722− toJSON (GeoBoundingBoxConstraint (FieldName geoBBField) constraintBox cache) =
723− object [geoBBField .= toJSON constraintBox
724− , "_cache" .= cache]
726−instance ToJSON GeoFilterType where
727− toJSON GeoFilterMemory = String "memory"
728− toJSON GeoFilterIndexed = String "indexed"
730−instance ToJSON GeoBoundingBox where
731− toJSON (GeoBoundingBox topLeft bottomRight) =
732− object ["top_left" .= toJSON topLeft
733− , "bottom_right" .= toJSON bottomRight]
735−instance ToJSON LatLon where
736− toJSON (LatLon lat lon) =
737− object ["lat" .= lat
741−newtype LessThan = LessThan Double deriving (Eq, Show)
742−newtype LessThanEq = LessThanEq Double deriving (Eq, Show)
743−newtype GreaterThan = GreaterThan Double deriving (Eq, Show)
744−newtype GreaterThanEq = GreaterThanEq Double deriving (Eq, Show)
746−data HalfRange = HalfRangeLt LessThan
747− | HalfRangeLte LessThanEq
748− | HalfRangeGt GreaterThan
749− | HalfRangeGte GreaterThanEq deriving (Eq, Show)
751−data Range = RangeLtGt LessThan GreaterThan
752− | RangeLtGte LessThan GreaterThanEq
753− | RangeLteGt LessThanEq GreaterThan
754− | RangeLteGte LessThanEq GreaterThanEq deriving (Eq, Show)
756−halfRangeToKV :: HalfRange -> (Text, Double)
757−halfRangeToKV (HalfRangeLt (LessThan n)) = ("lt", n)
758−halfRangeToKV (HalfRangeLte (LessThanEq n)) = ("lte", n)
759−halfRangeToKV (HalfRangeGt (GreaterThan n)) = ("gt", n)
760−halfRangeToKV (HalfRangeGte (GreaterThanEq n)) = ("gte", n)
762−rangeToKV :: Range -> (Text, Double, Text, Double)
763−rangeToKV (RangeLtGt (LessThan m) (GreaterThan n)) = ("lt", m, "gt", n)
764−rangeToKV (RangeLtGte (LessThan m) (GreaterThanEq n)) = ("lt", m, "gte", n)
765−rangeToKV (RangeLteGt (LessThanEq m) (GreaterThan n)) = ("lte", m, "gt", n)
766−rangeToKV (RangeLteGte (LessThanEq m) (GreaterThanEq n)) = ("lte", m, "gte", n)
768−data RangeExecution = RangeExecutionIndex
769− | RangeExecutionFielddata deriving (Eq, Show)
771−-- index for smaller ranges, fielddata for longer ranges
772−instance ToJSON RangeExecution where
773− toJSON RangeExecutionIndex = "index"
774− toJSON RangeExecutionFielddata = "fielddata"
776−newtype Regexp = Regexp Text deriving (Eq, Show)
777−data RegexpFlags = RegexpAll
785− | IntervalIntersection
787− | IntersectionAnyString deriving (Eq, Show)
789−instance ToJSON RegexpFlags where
790− toJSON RegexpAll = String "ALL"
791− toJSON Complement = String "COMPLEMENT"
792− toJSON Interval = String "INTERVAL"
793− toJSON Intersection = String "INTERSECTION"
794− toJSON AnyString = String "ANYSTRING"
795− toJSON CompInterval = String "COMPLEMENT|INTERVAL"
796− toJSON CompIntersection = String "COMPLEMENT|INTERSECTION"
797− toJSON CompAnyString = String "COMPLEMENT|ANYSTRING"
798− toJSON IntervalIntersection = String "INTERVAL|INTERSECTION"
799− toJSON IntervalAnyString = String "INTERVAL|ANYSTRING"
800− toJSON IntersectionAnyString = String "INTERSECTION|ANYSTRING"
802−-- phew. Coulda used Agda style case breaking there but, you know, whatever. :)
804−data Term = Term { termField :: Text
805− , termValue :: Text } deriving (Eq, Show)
807−instance ToJSON Term where
808− toJSON (Term field value) = object ["term" .= object
811−data BoolMatch = MustMatch Term Cache
812− | MustNotMatch Term Cache
813− | ShouldMatch [Term] Cache deriving (Eq, Show)
815−instance ToJSON BoolMatch where
816− toJSON (MustMatch term cache) = object ["must" .= toJSON term,
818− toJSON (MustNotMatch term cache) = object ["must_not" .= toJSON term,
820− toJSON (ShouldMatch terms cache) = object ["should" .= fmap toJSON terms,
823−-- "memory" or "indexed"
824−data GeoFilterType = GeoFilterMemory
825− | GeoFilterIndexed deriving (Eq, Show)
828−data LatLon = LatLon { lat :: Double
829− , lon :: Double } deriving (Eq, Show)
831−data GeoBoundingBox =
832− GeoBoundingBox { topLeft :: LatLon
833− , bottomRight :: LatLon } deriving (Eq, Show)
835−data GeoBoundingBoxConstraint =
836− GeoBoundingBoxConstraint { geoBBField :: FieldName
837− , constraintBox :: GeoBoundingBox
838− , bbConstraintcache :: Cache
839− } deriving (Eq, Show)
842− GeoPoint { geoField :: FieldName
843− , latLon :: LatLon} deriving (Eq, Show)
845−data DistanceUnit = Miles
853− | NauticalMiles deriving (Eq, Show)
855−data DistanceType = Arc
856− | SloppyArc -- doesn't exist <1.0
857− | Plane deriving (Eq, Show)
859−data OptimizeBbox = OptimizeGeoFilterType GeoFilterType
860− | NoOptimizeBbox deriving (Eq, Show)
863− Distance { coefficient :: Double
864− , unit :: DistanceUnit } deriving (Eq, Show)
867− DistanceRange { distanceFrom :: Distance
868− , distanceTo :: Distance } deriving (Eq, Show)
870−data FromJSON a => SearchResult a =
871− SearchResult { took :: Int
873− , shards :: ShardResult
874− , searchHits :: SearchHits a } deriving (Eq, Show)
878−data FromJSON a => SearchHits a =
879− SearchHits { hitsTotal :: Int
881− , hits :: [Hit a] } deriving (Eq, Show)
883−data FromJSON a => Hit a =
884− Hit { hitIndex :: IndexName
885− , hitType :: MappingName
888− , hitSource :: a } deriving (Eq, Show)
891− ShardResult { shardTotal :: Int
892− , shardsSuccessful :: Int
893− , shardsFailed :: Int } deriving (Eq, Show, Generic)
895−instance (FromJSON a, ToJSON a) => FromJSON (SearchResult a) where
896− parseJSON (Object v) = SearchResult <$>
898− v .: "timed_out" <*>
903−instance (FromJSON a, ToJSON a) => FromJSON (SearchHits a) where
904− parseJSON (Object v) = SearchHits <$>
906− v .: "max_score" <*>
910−instance (FromJSON a, ToJSON a) => FromJSON (Hit a) where
911− parseJSON (Object v) = Hit <$>
919−instance FromJSON ShardResult where
920− parseJSON (Object v) = ShardResult <$>
922− v .: "successful" <*>