-- |
-- Module      :  Network.Polkadot.Query
-- Copyright   :  Aleksandr Krupenkin 2016-2024
-- License     :  Apache-2.0
--
-- Maintainer  :  mail@akru.me
-- Stability   :  experimental
-- Portability :  unportable
--
-- Query storage for internal data.
--

module Network.Polkadot.Query where

import           Codec.Scale                  (Decode, decode)
import           Data.ByteArray.HexString     (HexString)
import           Data.Text                    (Text)
import           Network.JsonRpc.TinyClient   (JsonRpc)

import           Network.Polkadot.Metadata    (Metadata (Metadata),
                                               metadataTypes, toLatest)
import           Network.Polkadot.Rpc.State   (getMetadata, getStorage)
import           Network.Polkadot.Storage     (Storage, fromMetadata,
                                               storageKey)
import           Network.Polkadot.Storage.Key (Argument)

-- | Loads metadata from runtime and create storage type.
storage :: JsonRpc m => m (Either String Storage)
storage :: forall (m :: * -> *). JsonRpc m => m (Either String Storage)
storage = ((Metadata -> Storage)
-> Either String Metadata -> Either String Storage
forall a b. (a -> b) -> Either String a -> Either String b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Metadata -> Storage
go (Either String Metadata -> Either String Storage)
-> (HexString -> Either String Metadata)
-> HexString
-> Either String Storage
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HexString -> Either String Metadata
forall ba a.
(ByteArrayAccess ba, Decode a) =>
ba -> Either String a
decode) (HexString -> Either String Storage)
-> m HexString -> m (Either String Storage)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m HexString
forall (m :: * -> *). JsonRpc m => m HexString
getMetadata
  where
    go :: Metadata -> Storage
go Metadata
raw = let (Metadata
meta, Set Type
_) = Metadata -> (Metadata, Set Type)
metadataTypes Metadata
raw in Metadata -> Storage
fromMetadata (Metadata -> Metadata
toLatest Metadata
meta)

-- | Query data from blockchain via 'getStorage' RPC call.
query :: (JsonRpc m, Decode a)
      => Text
      -- ^ Module name.
      -> Text
      -- ^ Storage method name.
      -> [Argument]
      -- ^ Arguments (for mappings).
      -> m (Either String a)
      -- ^ Decoded storage item.
{-# INLINE query #-}
query :: forall (m :: * -> *) a.
(JsonRpc m, Decode a) =>
Text -> Text -> [Argument] -> m (Either String a)
query = Maybe HexString
-> Text -> Text -> [Argument] -> m (Either String a)
forall (m :: * -> *) a.
(JsonRpc m, Decode a) =>
Maybe HexString
-> Text -> Text -> [Argument] -> m (Either String a)
query' Maybe HexString
forall a. Maybe a
Nothing

-- | Similar to 'query' but get block hash for query as an argument.
query' :: (JsonRpc m, Decode a)
       => Maybe HexString
       -- ^ Block hash for query ('Nothing' for best block).
       -> Text
       -- ^ Module name.
       -> Text
       -- ^ Storage method name.
       -> [Argument]
       -- ^ Arguments (for mappings).
       -> m (Either String a)
       -- ^ Decoded storage item.
query' :: forall (m :: * -> *) a.
(JsonRpc m, Decode a) =>
Maybe HexString
-> Text -> Text -> [Argument] -> m (Either String a)
query' Maybe HexString
blockHash Text
section Text
method [Argument]
args = Either String Storage -> m (Either String a)
forall {f :: * -> *} {a}.
(Decode a, JsonRpc f) =>
Either String Storage -> f (Either String a)
go (Either String Storage -> m (Either String a))
-> m (Either String Storage) -> m (Either String a)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m (Either String Storage)
forall (m :: * -> *). JsonRpc m => m (Either String Storage)
storage
  where
    go :: Either String Storage -> f (Either String a)
go (Right Storage
store) = case Storage -> Text -> Text -> [Argument] -> Maybe HexString
storageKey Storage
store Text
section Text
method [Argument]
args of
        Just HexString
key -> HexString -> Either String a
forall ba a.
(ByteArrayAccess ba, Decode a) =>
ba -> Either String a
decode (HexString -> Either String a)
-> f HexString -> f (Either String a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HexString -> Maybe HexString -> f HexString
forall (m :: * -> *).
JsonRpc m =>
HexString -> Maybe HexString -> m HexString
getStorage HexString
key Maybe HexString
blockHash
        Maybe HexString
Nothing -> Either String a -> f (Either String a)
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String a
forall a b. a -> Either a b
Left String
"Unable to find given section/method or wrong argument count")
    go (Left String
err) = Either String a -> f (Either String a)
forall a. a -> f a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String a
forall a b. a -> Either a b
Left String
err)