module Tendermint.SDK.BaseApp.Query.Types
  (
  -- * Server combinators
    Leaf
  , QA
  , EmptyQueryServer(..)
  , QueryData(..)

  -- * Query Application
  , QueryApplication
  , QueryRequest(..)
  , parseQueryRequest
  , QueryArgs(..)
  , defaultQueryArgs
  , QueryResult(..)

  ) where

import           Control.Lens                           (from, lens, to, (^.))
import           Data.ByteArray.Base64String            (Base64String,
                                                         fromBytes, toBytes)
import           Data.Int                               (Int64)
import           Data.Kind                              (Type)
import           Data.Text                              (Text, breakOn, uncons)
import           Data.Word                              (Word64)
import           Network.ABCI.Types.Messages.FieldTypes (Proof, WrappedVal (..))
import qualified Network.ABCI.Types.Messages.Request    as Request
import qualified Network.ABCI.Types.Messages.Response   as Response
import           Tendermint.SDK.BaseApp.Router.Types    (HasPath (..))
import           Tendermint.SDK.BaseApp.Store           (RawKey (..))
import           Tendermint.SDK.Types.Address           (Address)

data Leaf (a :: Type)

data QA (a :: Type)

--------------------------------------------------------------------------------

type QueryApplication m = Request.Query -> m Response.Query

--------------------------------------------------------------------------------

data QueryRequest = QueryRequest
  { QueryRequest -> Text
queryRequestPath        :: Text
  , QueryRequest -> Text
queryRequestParamString :: Text
  , QueryRequest -> Base64String
queryRequestData        :: Base64String
  , QueryRequest -> Bool
queryRequestProve       :: Bool
  , QueryRequest -> Int64
queryRequestHeight      :: Int64
  } deriving (QueryRequest -> QueryRequest -> Bool
(QueryRequest -> QueryRequest -> Bool)
-> (QueryRequest -> QueryRequest -> Bool) -> Eq QueryRequest
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: QueryRequest -> QueryRequest -> Bool
$c/= :: QueryRequest -> QueryRequest -> Bool
== :: QueryRequest -> QueryRequest -> Bool
$c== :: QueryRequest -> QueryRequest -> Bool
Eq, Int -> QueryRequest -> ShowS
[QueryRequest] -> ShowS
QueryRequest -> String
(Int -> QueryRequest -> ShowS)
-> (QueryRequest -> String)
-> ([QueryRequest] -> ShowS)
-> Show QueryRequest
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [QueryRequest] -> ShowS
$cshowList :: [QueryRequest] -> ShowS
show :: QueryRequest -> String
$cshow :: QueryRequest -> String
showsPrec :: Int -> QueryRequest -> ShowS
$cshowsPrec :: Int -> QueryRequest -> ShowS
Show)

parseQueryRequest
  :: Request.Query
  -> QueryRequest
parseQueryRequest :: Query -> QueryRequest
parseQueryRequest Request.Query{..} =
  let (p :: Text
p, queryStrQ :: Text
queryStrQ) = Text -> Text -> (Text, Text)
breakOn "?" Text
queryPath
      queryStr :: Text
queryStr = case Text -> Maybe (Char, Text)
Data.Text.uncons Text
queryStrQ of
        Nothing -> ""
        Just ('?', rest :: Text
rest) -> Text
rest
        _ -> String -> Text
forall a. HasCallStack => String -> a
error "Impossible result parsing query string from path."
  in QueryRequest :: Text -> Text -> Base64String -> Bool -> Int64 -> QueryRequest
QueryRequest
       { queryRequestPath :: Text
queryRequestPath = Text
p
       , queryRequestParamString :: Text
queryRequestParamString = Text
queryStr
       , queryRequestData :: Base64String
queryRequestData = Base64String
queryData
       , queryRequestProve :: Bool
queryRequestProve = Bool
queryProve
       , queryRequestHeight :: Int64
queryRequestHeight = WrappedVal Int64 -> Int64
forall a. WrappedVal a -> a
unWrappedVal WrappedVal Int64
queryHeight
       }

instance HasPath QueryRequest where
  path :: (Text -> f Text) -> QueryRequest -> f QueryRequest
path = (QueryRequest -> Text)
-> (QueryRequest -> Text -> QueryRequest)
-> Lens' QueryRequest Text
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens QueryRequest -> Text
queryRequestPath (\q :: QueryRequest
q p :: Text
p -> QueryRequest
q {queryRequestPath :: Text
queryRequestPath = Text
p})

--------------------------------------------------------------------------------

data QueryArgs a = QueryArgs
  { QueryArgs a -> Bool
queryArgsProve  :: Bool
  , QueryArgs a -> a
queryArgsData   :: a
  , QueryArgs a -> Int64
queryArgsHeight :: Int64
  } deriving a -> QueryArgs b -> QueryArgs a
(a -> b) -> QueryArgs a -> QueryArgs b
(forall a b. (a -> b) -> QueryArgs a -> QueryArgs b)
-> (forall a b. a -> QueryArgs b -> QueryArgs a)
-> Functor QueryArgs
forall a b. a -> QueryArgs b -> QueryArgs a
forall a b. (a -> b) -> QueryArgs a -> QueryArgs b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> QueryArgs b -> QueryArgs a
$c<$ :: forall a b. a -> QueryArgs b -> QueryArgs a
fmap :: (a -> b) -> QueryArgs a -> QueryArgs b
$cfmap :: forall a b. (a -> b) -> QueryArgs a -> QueryArgs b
Functor

-- wrap data with default query fields
defaultQueryArgs :: QueryArgs ()
defaultQueryArgs :: QueryArgs ()
defaultQueryArgs = QueryArgs :: forall a. Bool -> a -> Int64 -> QueryArgs a
QueryArgs
  { queryArgsData :: ()
queryArgsData = ()
  , queryArgsHeight :: Int64
queryArgsHeight = -1
  , queryArgsProve :: Bool
queryArgsProve = Bool
False
  }

data QueryResult a = QueryResult
  { QueryResult a -> a
queryResultData   :: a
  , QueryResult a -> Int64
queryResultIndex  :: Int64
  , QueryResult a -> Base64String
queryResultKey    :: Base64String
  , QueryResult a -> Maybe Proof
queryResultProof  :: Maybe Proof
  , QueryResult a -> Int64
queryResultHeight :: Int64
  } deriving (QueryResult a -> QueryResult a -> Bool
(QueryResult a -> QueryResult a -> Bool)
-> (QueryResult a -> QueryResult a -> Bool) -> Eq (QueryResult a)
forall a. Eq a => QueryResult a -> QueryResult a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: QueryResult a -> QueryResult a -> Bool
$c/= :: forall a. Eq a => QueryResult a -> QueryResult a -> Bool
== :: QueryResult a -> QueryResult a -> Bool
$c== :: forall a. Eq a => QueryResult a -> QueryResult a -> Bool
Eq, Int -> QueryResult a -> ShowS
[QueryResult a] -> ShowS
QueryResult a -> String
(Int -> QueryResult a -> ShowS)
-> (QueryResult a -> String)
-> ([QueryResult a] -> ShowS)
-> Show (QueryResult a)
forall a. Show a => Int -> QueryResult a -> ShowS
forall a. Show a => [QueryResult a] -> ShowS
forall a. Show a => QueryResult a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [QueryResult a] -> ShowS
$cshowList :: forall a. Show a => [QueryResult a] -> ShowS
show :: QueryResult a -> String
$cshow :: forall a. Show a => QueryResult a -> String
showsPrec :: Int -> QueryResult a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> QueryResult a -> ShowS
Show, a -> QueryResult b -> QueryResult a
(a -> b) -> QueryResult a -> QueryResult b
(forall a b. (a -> b) -> QueryResult a -> QueryResult b)
-> (forall a b. a -> QueryResult b -> QueryResult a)
-> Functor QueryResult
forall a b. a -> QueryResult b -> QueryResult a
forall a b. (a -> b) -> QueryResult a -> QueryResult b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> QueryResult b -> QueryResult a
$c<$ :: forall a b. a -> QueryResult b -> QueryResult a
fmap :: (a -> b) -> QueryResult a -> QueryResult b
$cfmap :: forall a b. (a -> b) -> QueryResult a -> QueryResult b
Functor)

--------------------------------------------------------------------------------

-- | This class is used to parse the 'data' field of the query request message.
-- | The default method assumes that the 'data' is simply the key for the
-- | value being queried.
class QueryData a where
  fromQueryData :: Base64String -> Either String a
  toQueryData :: a -> Base64String

  default fromQueryData :: RawKey a => Base64String -> Either String a
  fromQueryData bs :: Base64String
bs = a -> Either String a
forall a b. b -> Either a b
Right (Base64String -> ByteString
forall ba. ByteArray ba => Base64String -> ba
toBytes Base64String
bs ByteString -> Getting a ByteString a -> a
forall s a. s -> Getting a s a -> a
^. AnIso a a ByteString ByteString -> Iso ByteString ByteString a a
forall s t a b. AnIso s t a b -> Iso b a t s
from AnIso a a ByteString ByteString
forall k. RawKey k => Iso' k ByteString
rawKey)

  default toQueryData :: RawKey a => a -> Base64String
  toQueryData k :: a
k = a
k a -> Getting Base64String a Base64String -> Base64String
forall s a. s -> Getting a s a -> a
^. (ByteString -> Const Base64String ByteString)
-> a -> Const Base64String a
forall k. RawKey k => Iso' k ByteString
rawKey ((ByteString -> Const Base64String ByteString)
 -> a -> Const Base64String a)
-> ((Base64String -> Const Base64String Base64String)
    -> ByteString -> Const Base64String ByteString)
-> Getting Base64String a Base64String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Base64String)
-> (Base64String -> Const Base64String Base64String)
-> ByteString
-> Const Base64String ByteString
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to ByteString -> Base64String
forall ba. ByteArrayAccess ba => ba -> Base64String
fromBytes

instance QueryData Address
instance QueryData Text
instance QueryData Word64
instance QueryData ()

data EmptyQueryServer = EmptyQueryServer