module Composite.Aeson.Formats.Provided where
import Composite.Aeson.Base (JsonFormat(JsonFormat), JsonProfunctor(JsonProfunctor), _JsonProfunctor, dimapJsonFormat, toJsonWithFormat)
import Composite.Aeson.Formats.Generic (SumStyle, abeJsonFormat, aesonJsonFormat, jsonArrayFormat, jsonObjectFormat, jsonSumFormat)
import Composite.Aeson.Formats.InternalTH (makeTupleFormats)
import Control.Arrow (first)
import Control.Lens (_2, _Wrapped, over, view)
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.BetterErrors as ABE
import Data.Fixed (HasResolution, Fixed)
import Data.Foldable (toList)
import Data.Hashable (Hashable)
import qualified Data.HashMap.Lazy as LazyHashMap
import qualified Data.HashMap.Strict as StrictHashMap
import Data.IntSet (IntSet)
import Data.List.NonEmpty (NonEmpty((:|)))
import qualified Data.List.NonEmpty as NEL
import qualified Data.Map.Lazy as LazyMap
import qualified Data.Map.Strict as StrictMap
import Data.Scientific (Scientific)
import qualified Data.Scientific as Scientific
import Data.Sequence (Seq)
import qualified Data.Sequence as Sequence
import Data.Text (Text)
import qualified Data.Text.Lazy as LT
import qualified Data.Vector as V
import Data.Version (Version)
import Numeric.Natural (Natural)
aesonArrayJsonFormat :: JsonFormat e Aeson.Array
aesonArrayJsonFormat = abeJsonFormat ABE.asArray
aesonObjectJsonFormat :: JsonFormat e Aeson.Object
aesonObjectJsonFormat = abeJsonFormat ABE.asObject
aesonValueJsonFormat :: JsonFormat e Aeson.Value
aesonValueJsonFormat = abeJsonFormat ABE.asValue
boolJsonFormat :: JsonFormat e Bool
boolJsonFormat = abeJsonFormat ABE.asBool
charJsonFormat :: JsonFormat e Char
charJsonFormat = aesonJsonFormat
eitherJsonFormat :: SumStyle -> Text -> Text -> JsonFormat e a -> JsonFormat e b -> JsonFormat e (Either a b)
eitherJsonFormat style leftName rightName leftFormat rightFormat = jsonSumFormat style o is
where
o = \ case
Left a -> (leftName, toJsonWithFormat leftFormat a)
Right b -> (rightName, toJsonWithFormat rightFormat b)
is =
(leftName, Left <$> view (_Wrapped . _JsonProfunctor . _2) leftFormat) :| [(rightName, Right <$> view (_Wrapped . _JsonProfunctor . _2) rightFormat)]
fixedJsonFormat :: HasResolution r => JsonFormat e (Fixed r)
fixedJsonFormat = aesonJsonFormat
strictHashMapJsonFormat :: (Eq k, Hashable k) => (k -> Text) -> (Text -> ABE.Parse e k) -> JsonFormat e a -> JsonFormat e (StrictHashMap.HashMap k a)
strictHashMapJsonFormat kToText kFromText =
jsonObjectFormat (fmap (first kToText) . StrictHashMap.toList)
(fmap StrictHashMap.fromList . traverse (\ (k, a) -> (, a) <$> kFromText k))
lazyHashMapJsonFormat :: (Eq k, Hashable k) => (k -> Text) -> (Text -> ABE.Parse e k) -> JsonFormat e a -> JsonFormat e (LazyHashMap.HashMap k a)
lazyHashMapJsonFormat kToText kFromText =
jsonObjectFormat (fmap (first kToText) . LazyHashMap.toList)
(fmap LazyHashMap.fromList . traverse (\ (k, a) -> (, a) <$> kFromText k))
intSetJsonFormat :: JsonFormat e IntSet
intSetJsonFormat = aesonJsonFormat
integralJsonFormat :: Integral a => JsonFormat e a
integralJsonFormat = JsonFormat $ JsonProfunctor (Aeson.Number . fromIntegral) ABE.asIntegral
lazyTextJsonFormat :: JsonFormat e LT.Text
lazyTextJsonFormat = dimapJsonFormat LT.toStrict LT.fromStrict textJsonFormat
listJsonFormat :: JsonFormat e a -> JsonFormat e [a]
listJsonFormat = jsonArrayFormat id pure
strictMapJsonFormat :: Ord k => (k -> Text) -> (Text -> ABE.Parse e k) -> JsonFormat e a -> JsonFormat e (StrictMap.Map k a)
strictMapJsonFormat kToText kFromText =
jsonObjectFormat (fmap (first kToText) . StrictMap.toAscList)
(fmap StrictMap.fromList . traverse (\ (k, a) -> (, a) <$> kFromText k))
lazyMapJsonFormat :: Ord k => (k -> Text) -> (Text -> ABE.Parse e k) -> JsonFormat e a -> JsonFormat e (LazyMap.Map k a)
lazyMapJsonFormat kToText kFromText =
jsonObjectFormat (fmap (first kToText) . LazyMap.toAscList)
(fmap LazyMap.fromList . traverse (\ (k, a) -> (, a) <$> kFromText k))
maybeJsonFormat :: JsonFormat e a -> JsonFormat e (Maybe a)
maybeJsonFormat =
over _Wrapped $ \ (JsonProfunctor o i) ->
JsonProfunctor (maybe Aeson.Null o) (ABE.perhaps i)
naturalJsonFormat :: JsonFormat e Natural
naturalJsonFormat = aesonJsonFormat
nonEmptyListJsonFormat :: JsonFormat e a -> JsonFormat e (NonEmpty a)
nonEmptyListJsonFormat =
jsonArrayFormat NEL.toList (maybe (fail "expected nonempty array") pure . NEL.nonEmpty)
nullJsonFormat :: JsonFormat e ()
nullJsonFormat = abeJsonFormat ABE.asNull
orderingJsonFormat :: JsonFormat e Ordering
orderingJsonFormat = aesonJsonFormat
realFloatJsonFormat :: RealFloat a => JsonFormat e a
realFloatJsonFormat = JsonFormat $ JsonProfunctor realFloatToJson ABE.asRealFloat
realFloatToJson :: RealFloat a => a -> Aeson.Value
realFloatToJson d
| isNaN d || isInfinite d = Aeson.Null
| otherwise = Aeson.Number $ Scientific.fromFloatDigits d
scientificJsonFormat :: JsonFormat e Scientific
scientificJsonFormat = abeJsonFormat ABE.asScientific
seqJsonFormat :: JsonFormat e a -> JsonFormat e (Seq a)
seqJsonFormat = jsonArrayFormat toList (pure . Sequence.fromList)
stringJsonFormat :: JsonFormat e String
stringJsonFormat = abeJsonFormat ABE.asString
textJsonFormat :: JsonFormat e Text
textJsonFormat = abeJsonFormat ABE.asText
$makeTupleFormats
unitJsonFormat :: JsonFormat e ()
unitJsonFormat = aesonJsonFormat
vectorJsonFormat :: JsonFormat e a -> JsonFormat e (V.Vector a)
vectorJsonFormat (JsonFormat (JsonProfunctor oA iA)) =
JsonFormat (JsonProfunctor o i)
where
o = Aeson.Array . fmap oA
i = V.fromList <$> ABE.eachInArray iA
versionJsonFormat :: JsonFormat e Version
versionJsonFormat = aesonJsonFormat