{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}

module Data.Aeson.Result
  ( Ok (..)
  , Err (..)
  , err
  , ok
  , fromOk
  , toOk
  , throwError

  , From
  , Size
  , Total
  , List (..)
  , emptyList
  , merge

  , toList
  , fromList
  ) where

import           Control.Exception (Exception, throwIO)
import           Data.Aeson        (FromJSON (..), Result (..), ToJSON (..),
                                    Value, fromJSON, object, withObject, (.:),
                                    (.=))
import           Data.Aeson.Helper (replace)
import           Data.Int          (Int64)
import           Data.Text         (Text)

type From  = Int64
type Size  = Int64
type Total = Int64

-- | Make ok result look like    '{"data": "data value"}'
newtype Ok a = Ok { Ok a -> a
getValue :: a }
  deriving (Int -> Ok a -> ShowS
[Ok a] -> ShowS
Ok a -> String
(Int -> Ok a -> ShowS)
-> (Ok a -> String) -> ([Ok a] -> ShowS) -> Show (Ok a)
forall a. Show a => Int -> Ok a -> ShowS
forall a. Show a => [Ok a] -> ShowS
forall a. Show a => Ok a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Ok a] -> ShowS
$cshowList :: forall a. Show a => [Ok a] -> ShowS
show :: Ok a -> String
$cshow :: forall a. Show a => Ok a -> String
showsPrec :: Int -> Ok a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Ok a -> ShowS
Show)

instance (FromJSON a) => FromJSON (Ok a) where
  parseJSON :: Value -> Parser (Ok a)
parseJSON = String -> (Object -> Parser (Ok a)) -> Value -> Parser (Ok a)
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject "Ok" ((Object -> Parser (Ok a)) -> Value -> Parser (Ok a))
-> (Object -> Parser (Ok a)) -> Value -> Parser (Ok a)
forall a b. (a -> b) -> a -> b
$ \o :: Object
o -> do
    a
getValue <- Object
o Object -> Text -> Parser a
forall a. FromJSON a => Object -> Text -> Parser a
.: "result"
    Ok a -> Parser (Ok a)
forall (m :: * -> *) a. Monad m => a -> m a
return Ok :: forall a. a -> Ok a
Ok{..}

instance (ToJSON a) => ToJSON (Ok a) where
  toJSON :: Ok a -> Value
toJSON Ok{..} = [Pair] -> Value
object [ "result" Text -> a -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= a
getValue ]

-- | Make error result look like    '{"err": "error message"}'
newtype Err = Err { Err -> String
errMsg :: String }
  deriving (Int -> Err -> ShowS
[Err] -> ShowS
Err -> String
(Int -> Err -> ShowS)
-> (Err -> String) -> ([Err] -> ShowS) -> Show Err
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Err] -> ShowS
$cshowList :: [Err] -> ShowS
show :: Err -> String
$cshow :: Err -> String
showsPrec :: Int -> Err -> ShowS
$cshowsPrec :: Int -> Err -> ShowS
Show, Err -> Err -> Bool
(Err -> Err -> Bool) -> (Err -> Err -> Bool) -> Eq Err
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Err -> Err -> Bool
$c/= :: Err -> Err -> Bool
== :: Err -> Err -> Bool
$c== :: Err -> Err -> Bool
Eq, Eq Err
Eq Err =>
(Err -> Err -> Ordering)
-> (Err -> Err -> Bool)
-> (Err -> Err -> Bool)
-> (Err -> Err -> Bool)
-> (Err -> Err -> Bool)
-> (Err -> Err -> Err)
-> (Err -> Err -> Err)
-> Ord Err
Err -> Err -> Bool
Err -> Err -> Ordering
Err -> Err -> Err
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Err -> Err -> Err
$cmin :: Err -> Err -> Err
max :: Err -> Err -> Err
$cmax :: Err -> Err -> Err
>= :: Err -> Err -> Bool
$c>= :: Err -> Err -> Bool
> :: Err -> Err -> Bool
$c> :: Err -> Err -> Bool
<= :: Err -> Err -> Bool
$c<= :: Err -> Err -> Bool
< :: Err -> Err -> Bool
$c< :: Err -> Err -> Bool
compare :: Err -> Err -> Ordering
$ccompare :: Err -> Err -> Ordering
$cp1Ord :: Eq Err
Ord)

instance Exception Err

-- | Throw error to IO
throwError :: Err -> IO a
throwError :: Err -> IO a
throwError = Err -> IO a
forall e a. Exception e => e -> IO a
throwIO

instance FromJSON Err where
  parseJSON :: Value -> Parser Err
parseJSON = String -> (Object -> Parser Err) -> Value -> Parser Err
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject "Err" ((Object -> Parser Err) -> Value -> Parser Err)
-> (Object -> Parser Err) -> Value -> Parser Err
forall a b. (a -> b) -> a -> b
$ \o :: Object
o -> do
    String
errMsg <- Object
o Object -> Text -> Parser String
forall a. FromJSON a => Object -> Text -> Parser a
.: "err"
    Err -> Parser Err
forall (m :: * -> *) a. Monad m => a -> m a
return Err :: String -> Err
Err{..}

instance ToJSON Err where
  toJSON :: Err -> Value
toJSON Err{..} = [Pair] -> Value
object [ "err" Text -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= String
errMsg ]

-- | Initial Err
err :: String -> Err
err :: String -> Err
err = String -> Err
Err


-- | Initial Ok
ok :: a -> Ok a
ok :: a -> Ok a
ok = a -> Ok a
forall a. a -> Ok a
Ok

-- | Make a JSON result to Ok
toOk :: FromJSON a => Text -> Value -> Maybe (Ok a)
toOk :: Text -> Value -> Maybe (Ok a)
toOk okey :: Text
okey v :: Value
v =
  case Value -> Result (Ok a)
forall a. FromJSON a => Value -> Result a
fromJSON (Text -> Text -> Value -> Value
replace Text
okey "result" Value
v) of
    Success v' :: Ok a
v' -> Ok a -> Maybe (Ok a)
forall a. a -> Maybe a
Just Ok a
v'
    _          -> Maybe (Ok a)
forall a. Maybe a
Nothing

-- | Make an Ok to JSON
fromOk :: ToJSON a => Text -> Ok a -> Value
fromOk :: Text -> Ok a -> Value
fromOk key :: Text
key ret :: Ok a
ret = Text -> Text -> Value -> Value
replace "result" Text
key (Value -> Value) -> Value -> Value
forall a b. (a -> b) -> a -> b
$ Ok a -> Value
forall a. ToJSON a => a -> Value
toJSON Ok a
ret

-- | Make list result look like '{"users": ["user1"], "total": 1, "from": 0, "size": 10}'
data List a = List
  { List a -> From
getFrom   :: From
  , List a -> From
getSize   :: Size
  , List a -> From
getTotal  :: Total
  , List a -> [a]
getResult :: [a]
  }
  deriving (Int -> List a -> ShowS
[List a] -> ShowS
List a -> String
(Int -> List a -> ShowS)
-> (List a -> String) -> ([List a] -> ShowS) -> Show (List a)
forall a. Show a => Int -> List a -> ShowS
forall a. Show a => [List a] -> ShowS
forall a. Show a => List a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [List a] -> ShowS
$cshowList :: forall a. Show a => [List a] -> ShowS
show :: List a -> String
$cshow :: forall a. Show a => List a -> String
showsPrec :: Int -> List a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> List a -> ShowS
Show)


instance FromJSON a => FromJSON (List a) where
  parseJSON :: Value -> Parser (List a)
parseJSON = String -> (Object -> Parser (List a)) -> Value -> Parser (List a)
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject "List" ((Object -> Parser (List a)) -> Value -> Parser (List a))
-> (Object -> Parser (List a)) -> Value -> Parser (List a)
forall a b. (a -> b) -> a -> b
$ \o :: Object
o -> do
    From
getFrom   <- Object
o Object -> Text -> Parser From
forall a. FromJSON a => Object -> Text -> Parser a
.: "from"
    From
getSize   <- Object
o Object -> Text -> Parser From
forall a. FromJSON a => Object -> Text -> Parser a
.: "size"
    From
getTotal  <- Object
o Object -> Text -> Parser From
forall a. FromJSON a => Object -> Text -> Parser a
.: "total"
    [a]
getResult <- Object
o Object -> Text -> Parser [a]
forall a. FromJSON a => Object -> Text -> Parser a
.: "result"
    List a -> Parser (List a)
forall (m :: * -> *) a. Monad m => a -> m a
return List :: forall a. From -> From -> From -> [a] -> List a
List{..}

instance ToJSON a => ToJSON (List a) where
  toJSON :: List a -> Value
toJSON List{..} = [Pair] -> Value
object
    [ "from"   Text -> From -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= From
getFrom
    , "size"   Text -> From -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= From
getSize
    , "total"  Text -> From -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= From
getTotal
    , "result" Text -> [a] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [a]
getResult
    ]

-- | Empty list
emptyList :: List a
emptyList :: List a
emptyList = List :: forall a. From -> From -> From -> [a] -> List a
List
  { getFrom :: From
getFrom = 0
  , getSize :: From
getSize = 10
  , getTotal :: From
getTotal = 0
  , getResult :: [a]
getResult = []
  }

-- | Merge two list, from size and total, result is replace.
merge :: [a] -> List b -> List a
merge :: [a] -> List b -> List a
merge t :: [a]
t List
  { getFrom :: forall a. List a -> From
getFrom = From
from
  , getSize :: forall a. List a -> From
getSize = From
size
  , getTotal :: forall a. List a -> From
getTotal = From
total
  } = List :: forall a. From -> From -> From -> [a] -> List a
List
  { getFrom :: From
getFrom = From
from
  , getSize :: From
getSize = From
size
  , getTotal :: From
getTotal = From
total
  , getResult :: [a]
getResult = [a]
t
  }

-- | Make a JSON to List
toList :: FromJSON a => Text -> Value -> Maybe (List a)
toList :: Text -> Value -> Maybe (List a)
toList okey :: Text
okey v :: Value
v =
  case Value -> Result (List a)
forall a. FromJSON a => Value -> Result a
fromJSON (Text -> Text -> Value -> Value
replace Text
okey "result" Value
v) of
    Success v' :: List a
v' -> List a -> Maybe (List a)
forall a. a -> Maybe a
Just List a
v'
    _          -> Maybe (List a)
forall a. Maybe a
Nothing

-- | Make a List to JSON
fromList :: ToJSON a => Text -> List a -> Value
fromList :: Text -> List a -> Value
fromList key :: Text
key ret :: List a
ret = Text -> Text -> Value -> Value
replace "result" Text
key (Value -> Value) -> Value -> Value
forall a b. (a -> b) -> a -> b
$ List a -> Value
forall a. ToJSON a => a -> Value
toJSON List a
ret