{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.Aeson.Extra.SingObject (
SingObject(..),
mkSingObject,
getSingObject,
) where
import Prelude ()
import Prelude.Compat
import Control.DeepSeq (NFData (..))
import Data.Aeson.Compat
import Data.Proxy (Proxy (..))
import Data.Semigroup.Compat ((<>))
import Data.Typeable (Typeable)
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import qualified Data.Text as T
#if MIN_VERSION_aeson(1,0,0)
import Data.Aeson.Encoding (pair)
import Data.Aeson.Internal (JSONPathElement (Key), (<?>))
import Data.Aeson.Types hiding ((.:?))
import qualified Data.HashMap.Strict as HM
#endif
newtype SingObject (s :: Symbol) a = SingObject a
deriving (Eq, Ord, Show, Read, Functor, Foldable, Traversable, Typeable)
mkSingObject :: Proxy s -> a -> SingObject s a
mkSingObject _ = SingObject
getSingObject :: Proxy s -> SingObject s a -> a
getSingObject _ (SingObject x) = x
#if MIN_VERSION_aeson(1,0,0)
instance KnownSymbol s => FromJSON1 (SingObject s) where
liftParseJSON p _ = withObject ("SingObject "<> show key) $ \obj ->
case HM.lookup key obj of
Nothing -> fail $ "key " ++ show key ++ " not present"
Just v -> SingObject <$> p v <?> Key key
where
key = T.pack $ symbolVal (Proxy :: Proxy s)
instance KnownSymbol s => ToJSON1 (SingObject s) where
liftToJSON to _ (SingObject x) =
object [ key .= to x]
where
key = T.pack $ symbolVal (Proxy :: Proxy s)
liftToEncoding to _ (SingObject x) =
pairs $ pair key $ to x
where
key = T.pack $ symbolVal (Proxy :: Proxy s)
instance (KnownSymbol s, FromJSON a) => FromJSON (SingObject s a) where
parseJSON = parseJSON1
instance (KnownSymbol s, ToJSON a) => ToJSON (SingObject s a) where
toJSON = toJSON1
toEncoding = toEncoding1
#else
instance (KnownSymbol s, FromJSON a) => FromJSON (SingObject s a) where
parseJSON = withObject ("SingObject "<> show key) $ \obj ->
SingObject <$> obj .: T.pack key
where key = symbolVal (Proxy :: Proxy s)
instance (KnownSymbol s, ToJSON a) => ToJSON (SingObject s a) where
#if MIN_VERSION_aeson(0,10,0)
toEncoding (SingObject x) = pairs (T.pack key .= x)
where key = symbolVal (Proxy :: Proxy s)
#endif
toJSON (SingObject x) = object [T.pack key .= x]
where key = symbolVal (Proxy :: Proxy s)
#endif
instance NFData a => NFData (SingObject s a) where
rnf (SingObject x) = rnf x