waargonaut-0.6.0.0: src/Waargonaut/Lens.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
module Waargonaut.Lens
(
-- * Prisms
_TextJson
, _Number
, _String
, _Bool
, _ArrayOf
, _ObjHashMapOf
, _Null
) where
import Prelude (Bool, Show)
import Control.Applicative (liftA2)
import Control.Category ((.))
import Control.Error.Util (note)
import Control.Lens (Prism', cons, preview, prism,
review, (^?), _1, _Wrapped)
import Control.Monad (Monad, void)
import Data.Foldable (foldr)
import Data.Function (const, ($))
import Data.Functor (fmap)
import Data.Scientific (Scientific)
import Data.Tuple (uncurry)
import Data.Bifunctor (first)
import Data.Either (Either (..))
import Text.Parser.Char (CharParsing)
import Data.Text (Text)
import qualified Data.Text.Lazy as TL
import Data.Vector (Vector)
import qualified Data.Vector as V
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HM
import qualified Waargonaut.Types.JObject.JAssoc as JA
import qualified Waargonaut.Types.CommaSep as CS
import Waargonaut.Types.JString (_JStringText)
import Waargonaut.Types.JNumber (_JNumberScientific)
import Waargonaut.Types.Json (AsJType (..), Json)
import qualified Waargonaut.Decode as D
import qualified Waargonaut.Encode as E
-- | 'Prism'' between 'Json' and 'Text'
_TextJson
:: ( CharParsing g
, Monad g
, Show e
)
=> (forall a. g a -> Text -> Either e a)
-> Prism' Text Json
_TextJson pf = prism
(TL.toStrict . E.simplePureEncodeText E.json)
(\b -> first (const b) $ D.pureDecodeFromText pf D.json b)
{-# INLINE _TextJson #-}
-- | 'Prism'' between some 'Json' and a 'Scientific' value
_Number :: Prism' Json Scientific
_Number = prism (E.asJson' E.scientific) (\j -> note j $ j ^? _JNum . _1 . _JNumberScientific)
{-# INLINE _Number #-}
-- | 'Prism'' between some 'Json' and a 'Text' value
_String :: Prism' Json Text
_String = prism (E.asJson' E.text) (\j -> note j $ j ^? _JStr . _1 . _JStringText)
{-# INLINE _String #-}
-- | 'Prism'' between some 'Json' and a '()' value
_Null :: Prism' Json ()
_Null = prism (E.asJson' E.null) (\j -> note j . void $ j ^? _JNull)
{-# INLINE _Null #-}
-- | 'Prism'' between some 'Json' and a 'Bool' value
_Bool :: Prism' Json Bool
_Bool = prism (E.asJson' E.bool) (\j -> note j $ j ^? _JBool . _1)
{-# INLINE _Bool#-}
-- | 'Prism'' between some 'Json' and an array of something given the provided 'Prism''
_ArrayOf :: Prism' Json x -> Prism' Json (Vector x)
_ArrayOf _Value = prism fromJ toJ
where
fromJ = E.asJson' (E.traversable E.json) . fmap (review _Value)
{-# INLINE fromJ #-}
toJ = CS.fromCommaSep (_JArr . _1 . _Wrapped) V.empty (foldr cons V.empty) (preview _Value)
{-# INLINE toJ #-}
{-# INLINE _ArrayOf #-}
-- | 'Prism'' between some 'Json' and a strict 'HashMap' with 'Text' keys, and
-- some value of a type provided by the given @Prism' Json x@.
_ObjHashMapOf :: Prism' Json x -> Prism' Json (HashMap Text x)
_ObjHashMapOf _Value = prism toJ fromJ
where
toJ = E.asJson' (E.keyValueTupleFoldable (E.prismE _Value E.json)) . HM.toList
{-# INLINE toJ #-}
toVals el = liftA2 (,)
(preview (JA.jsonAssocKey . _JStringText) el)
(preview (JA.jsonAssocVal . _Value) el)
{-# INLINE toVals #-}
fromJ = CS.fromCommaSep (_JObj . _1 . _Wrapped) HM.empty
(foldr (uncurry HM.insert) HM.empty) toVals
{-# INLINE fromJ #-}
{-# INLINE _ObjHashMapOf #-}