{-# LANGUAGE OverloadedStrings #-}

module Database.Bloodhound.Internal.Versions.Common.Types.Query.Commons
  ( BooleanOperator (..),
    Fuzziness (..),
    ZeroTermsQuery (..),
    fieldTagged,
  )
where

import qualified Data.Aeson.KeyMap as X
import Database.Bloodhound.Internal.Utils.Imports
import Database.Bloodhound.Internal.Versions.Common.Types.Newtypes
import GHC.Generics

data ZeroTermsQuery
  = ZeroTermsNone
  | ZeroTermsAll
  deriving stock (ZeroTermsQuery -> ZeroTermsQuery -> Bool
(ZeroTermsQuery -> ZeroTermsQuery -> Bool)
-> (ZeroTermsQuery -> ZeroTermsQuery -> Bool) -> Eq ZeroTermsQuery
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ZeroTermsQuery -> ZeroTermsQuery -> Bool
== :: ZeroTermsQuery -> ZeroTermsQuery -> Bool
$c/= :: ZeroTermsQuery -> ZeroTermsQuery -> Bool
/= :: ZeroTermsQuery -> ZeroTermsQuery -> Bool
Eq, Int -> ZeroTermsQuery -> ShowS
[ZeroTermsQuery] -> ShowS
ZeroTermsQuery -> String
(Int -> ZeroTermsQuery -> ShowS)
-> (ZeroTermsQuery -> String)
-> ([ZeroTermsQuery] -> ShowS)
-> Show ZeroTermsQuery
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ZeroTermsQuery -> ShowS
showsPrec :: Int -> ZeroTermsQuery -> ShowS
$cshow :: ZeroTermsQuery -> String
show :: ZeroTermsQuery -> String
$cshowList :: [ZeroTermsQuery] -> ShowS
showList :: [ZeroTermsQuery] -> ShowS
Show, (forall x. ZeroTermsQuery -> Rep ZeroTermsQuery x)
-> (forall x. Rep ZeroTermsQuery x -> ZeroTermsQuery)
-> Generic ZeroTermsQuery
forall x. Rep ZeroTermsQuery x -> ZeroTermsQuery
forall x. ZeroTermsQuery -> Rep ZeroTermsQuery x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ZeroTermsQuery -> Rep ZeroTermsQuery x
from :: forall x. ZeroTermsQuery -> Rep ZeroTermsQuery x
$cto :: forall x. Rep ZeroTermsQuery x -> ZeroTermsQuery
to :: forall x. Rep ZeroTermsQuery x -> ZeroTermsQuery
Generic)

instance ToJSON ZeroTermsQuery where
  toJSON :: ZeroTermsQuery -> Value
toJSON ZeroTermsQuery
ZeroTermsNone = Text -> Value
String Text
"none"
  toJSON ZeroTermsQuery
ZeroTermsAll = Text -> Value
String Text
"all"

instance FromJSON ZeroTermsQuery where
  parseJSON :: Value -> Parser ZeroTermsQuery
parseJSON = String
-> (Text -> Parser ZeroTermsQuery)
-> Value
-> Parser ZeroTermsQuery
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"ZeroTermsQuery" Text -> Parser ZeroTermsQuery
forall {a} {f :: * -> *}.
(Eq a, IsString a, MonadFail f, Show a) =>
a -> f ZeroTermsQuery
parse
    where
      parse :: a -> f ZeroTermsQuery
parse a
"none" = ZeroTermsQuery -> f ZeroTermsQuery
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ZeroTermsQuery
ZeroTermsNone
      parse a
"all" = ZeroTermsQuery -> f ZeroTermsQuery
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ZeroTermsQuery
ZeroTermsAll
      parse a
q = String -> f ZeroTermsQuery
forall a. String -> f a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
"Unexpected ZeroTermsQuery: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> a -> String
forall a. Show a => a -> String
show a
q)

-- | 'BooleanOperator' is the usual And/Or operators with an ES compatible
--   JSON encoding baked in. Used all over the place.
data BooleanOperator = And | Or deriving stock (BooleanOperator -> BooleanOperator -> Bool
(BooleanOperator -> BooleanOperator -> Bool)
-> (BooleanOperator -> BooleanOperator -> Bool)
-> Eq BooleanOperator
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BooleanOperator -> BooleanOperator -> Bool
== :: BooleanOperator -> BooleanOperator -> Bool
$c/= :: BooleanOperator -> BooleanOperator -> Bool
/= :: BooleanOperator -> BooleanOperator -> Bool
Eq, Int -> BooleanOperator -> ShowS
[BooleanOperator] -> ShowS
BooleanOperator -> String
(Int -> BooleanOperator -> ShowS)
-> (BooleanOperator -> String)
-> ([BooleanOperator] -> ShowS)
-> Show BooleanOperator
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BooleanOperator -> ShowS
showsPrec :: Int -> BooleanOperator -> ShowS
$cshow :: BooleanOperator -> String
show :: BooleanOperator -> String
$cshowList :: [BooleanOperator] -> ShowS
showList :: [BooleanOperator] -> ShowS
Show, (forall x. BooleanOperator -> Rep BooleanOperator x)
-> (forall x. Rep BooleanOperator x -> BooleanOperator)
-> Generic BooleanOperator
forall x. Rep BooleanOperator x -> BooleanOperator
forall x. BooleanOperator -> Rep BooleanOperator x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BooleanOperator -> Rep BooleanOperator x
from :: forall x. BooleanOperator -> Rep BooleanOperator x
$cto :: forall x. Rep BooleanOperator x -> BooleanOperator
to :: forall x. Rep BooleanOperator x -> BooleanOperator
Generic)

instance ToJSON BooleanOperator where
  toJSON :: BooleanOperator -> Value
toJSON BooleanOperator
And = Text -> Value
String Text
"and"
  toJSON BooleanOperator
Or = Text -> Value
String Text
"or"

instance FromJSON BooleanOperator where
  parseJSON :: Value -> Parser BooleanOperator
parseJSON = String
-> (Text -> Parser BooleanOperator)
-> Value
-> Parser BooleanOperator
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText String
"BooleanOperator" Text -> Parser BooleanOperator
forall {a} {f :: * -> *}.
(Eq a, IsString a, MonadFail f, Show a) =>
a -> f BooleanOperator
parse
    where
      parse :: a -> f BooleanOperator
parse a
"and" = BooleanOperator -> f BooleanOperator
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure BooleanOperator
And
      parse a
"or" = BooleanOperator -> f BooleanOperator
forall a. a -> f a
forall (f :: * -> *) a. Applicative f => a -> f a
pure BooleanOperator
Or
      parse a
o = String -> f BooleanOperator
forall a. String -> f a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String
"Unexpected BooleanOperator: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> a -> String
forall a. Show a => a -> String
show a
o)

-- | Fuzziness value as a number or 'AUTO'.
-- See:
-- https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#fuzziness
data Fuzziness = Fuzziness Double | FuzzinessAuto
  deriving stock (Fuzziness -> Fuzziness -> Bool
(Fuzziness -> Fuzziness -> Bool)
-> (Fuzziness -> Fuzziness -> Bool) -> Eq Fuzziness
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Fuzziness -> Fuzziness -> Bool
== :: Fuzziness -> Fuzziness -> Bool
$c/= :: Fuzziness -> Fuzziness -> Bool
/= :: Fuzziness -> Fuzziness -> Bool
Eq, Int -> Fuzziness -> ShowS
[Fuzziness] -> ShowS
Fuzziness -> String
(Int -> Fuzziness -> ShowS)
-> (Fuzziness -> String)
-> ([Fuzziness] -> ShowS)
-> Show Fuzziness
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Fuzziness -> ShowS
showsPrec :: Int -> Fuzziness -> ShowS
$cshow :: Fuzziness -> String
show :: Fuzziness -> String
$cshowList :: [Fuzziness] -> ShowS
showList :: [Fuzziness] -> ShowS
Show, (forall x. Fuzziness -> Rep Fuzziness x)
-> (forall x. Rep Fuzziness x -> Fuzziness) -> Generic Fuzziness
forall x. Rep Fuzziness x -> Fuzziness
forall x. Fuzziness -> Rep Fuzziness x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Fuzziness -> Rep Fuzziness x
from :: forall x. Fuzziness -> Rep Fuzziness x
$cto :: forall x. Rep Fuzziness x -> Fuzziness
to :: forall x. Rep Fuzziness x -> Fuzziness
Generic)

instance ToJSON Fuzziness where
  toJSON :: Fuzziness -> Value
toJSON (Fuzziness Double
n) = Double -> Value
forall a. ToJSON a => a -> Value
toJSON Double
n
  toJSON Fuzziness
FuzzinessAuto = Text -> Value
String Text
"AUTO"

instance FromJSON Fuzziness where
  parseJSON :: Value -> Parser Fuzziness
parseJSON (String Text
"AUTO") = Fuzziness -> Parser Fuzziness
forall a. a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return Fuzziness
FuzzinessAuto
  parseJSON Value
v = Double -> Fuzziness
Fuzziness (Double -> Fuzziness) -> Parser Double -> Parser Fuzziness
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser Double
forall a. FromJSON a => Value -> Parser a
parseJSON Value
v

fieldTagged :: (Monad m, MonadFail m) => (FieldName -> Object -> m a) -> Object -> m a
fieldTagged :: forall (m :: * -> *) a.
(Monad m, MonadFail m) =>
(FieldName -> Object -> m a) -> Object -> m a
fieldTagged FieldName -> Object -> m a
f Object
o = case Object -> [(Key, Value)]
forall v. KeyMap v -> [(Key, v)]
X.toList Object
o of
  [(Key
k, Object Object
o')] -> FieldName -> Object -> m a
f (Text -> FieldName
FieldName (Text -> FieldName) -> Text -> FieldName
forall a b. (a -> b) -> a -> b
$ Key -> Text
toText Key
k) Object
o'
  [(Key, Value)]
_ -> String -> m a
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Expected object with 1 field-named key"