{-# 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.Aeson.Key    (Key)
import           Data.Int          (Int64)

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 String
"Ok" ((Object -> Parser (Ok a)) -> Value -> Parser (Ok a))
-> (Object -> Parser (Ok a)) -> Value -> Parser (Ok a)
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    a
getValue <- Object
o Object -> Key -> Parser a
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"result"
    Ok a -> Parser (Ok a)
forall (m :: * -> *) a. Monad m => a -> m a
return Ok :: forall a. a -> Ok a
Ok{a
getValue :: a
getValue :: a
..}

instance (ToJSON a) => ToJSON (Ok a) where
  toJSON :: Ok a -> Value
toJSON Ok{a
getValue :: a
getValue :: forall a. Ok a -> a
..} = [Pair] -> Value
object [ Key
"result" Key -> a -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> 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 String
"Err" ((Object -> Parser Err) -> Value -> Parser Err)
-> (Object -> Parser Err) -> Value -> Parser Err
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    String
errMsg <- Object
o Object -> Key -> Parser String
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"err"
    Err -> Parser Err
forall (m :: * -> *) a. Monad m => a -> m a
return Err :: String -> Err
Err{String
errMsg :: String
errMsg :: String
..}

instance ToJSON Err where
  toJSON :: Err -> Value
toJSON Err{String
errMsg :: String
errMsg :: Err -> String
..} = [Pair] -> Value
object [ Key
"err" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> 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 => Key -> Value -> Maybe (Ok a)
toOk :: Key -> Value -> Maybe (Ok a)
toOk Key
okey Value
v =
  case Value -> Result (Ok a)
forall a. FromJSON a => Value -> Result a
fromJSON (Key -> Key -> Value -> Value
replace Key
okey Key
"result" Value
v) of
    Success Ok a
v' -> Ok a -> Maybe (Ok a)
forall a. a -> Maybe a
Just Ok a
v'
    Result (Ok a)
_          -> Maybe (Ok a)
forall a. Maybe a
Nothing

-- | Make an Ok to JSON
fromOk :: ToJSON a => Key -> Ok a -> Value
fromOk :: Key -> Ok a -> Value
fromOk Key
key Ok a
ret = Key -> Key -> Value -> Value
replace Key
"result" Key
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 String
"List" ((Object -> Parser (List a)) -> Value -> Parser (List a))
-> (Object -> Parser (List a)) -> Value -> Parser (List a)
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    From
getFrom   <- Object
o Object -> Key -> Parser From
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"from"
    From
getSize   <- Object
o Object -> Key -> Parser From
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"size"
    From
getTotal  <- Object
o Object -> Key -> Parser From
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"total"
    [a]
getResult <- Object
o Object -> Key -> Parser [a]
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"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{From
[a]
getResult :: [a]
getTotal :: From
getSize :: From
getFrom :: From
getResult :: [a]
getTotal :: From
getSize :: From
getFrom :: From
..}

instance ToJSON a => ToJSON (List a) where
  toJSON :: List a -> Value
toJSON List{From
[a]
getResult :: [a]
getTotal :: From
getSize :: From
getFrom :: From
getResult :: forall a. List a -> [a]
getTotal :: forall a. List a -> From
getSize :: forall a. List a -> From
getFrom :: forall a. List a -> From
..} = [Pair] -> Value
object
    [ Key
"from"   Key -> From -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= From
getFrom
    , Key
"size"   Key -> From -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= From
getSize
    , Key
"total"  Key -> From -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= From
getTotal
    , Key
"result" Key -> [a] -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> 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 = From
0
  , getSize :: From
getSize = From
10
  , getTotal :: From
getTotal = From
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 [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 => Key -> Value -> Maybe (List a)
toList :: Key -> Value -> Maybe (List a)
toList Key
okey Value
v =
  case Value -> Result (List a)
forall a. FromJSON a => Value -> Result a
fromJSON (Key -> Key -> Value -> Value
replace Key
okey Key
"result" Value
v) of
    Success List a
v' -> List a -> Maybe (List a)
forall a. a -> Maybe a
Just List a
v'
    Result (List a)
_          -> Maybe (List a)
forall a. Maybe a
Nothing

-- | Make a List to JSON
fromList :: ToJSON a => Key -> List a -> Value
fromList :: Key -> List a -> Value
fromList Key
key List a
ret = Key -> Key -> Value -> Value
replace Key
"result" Key
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