module Calamity.Internal.AesonThings
( WithSpecialCases
, WithSpecialCasesInner(..)
, type IfNoneThen
, type ExtractField
, type ExtractFields
, type InjectID
, SpecialRule
, DefaultToEmptyArray
, DefaultToZero
, DefaultToFalse
, CalamityJSON(..)
, jsonOptions
, jsonOptionsKeepNothing ) where
import Control.Lens
import Data.Aeson
import Data.Aeson.Lens
import Data.Aeson.Types ( Parser )
import Data.Kind
import Data.Reflection ( Reifies(..) )
import Data.Text ( Text )
import Data.Text.Strict.Lens
import Data.Typeable
import GHC.Generics
import qualified GHC.TypeLits as TL
import GHC.TypeLits ( KnownSymbol, Symbol, symbolVal )
textSymbolVal :: forall n. KnownSymbol n => Proxy n -> Text
textSymbolVal :: Proxy n -> Text
textSymbolVal _ = Proxy n -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal @n Proxy n
forall k (t :: k). Proxy t
Proxy String -> Getting Text String Text -> Text
forall s a. s -> Getting a s a -> a
^. Getting Text String Text
Iso' String Text
packed
data SpecialCaseList
= SpecialCaseNil
| forall label action inner. SpecialCaseElem label action inner
data SpecialRule (label :: Symbol) (action :: SpecialRuleAction)
data SpecialRuleAction
= forall d. IfNoneThen d
| forall field. field
| forall field. field
| forall mn idn. InjectID idn mn
type IfNoneThen label d =
SpecialRule label ('IfNoneThen d)
type label field =
SpecialRule label ('ExtractField field)
type label field =
SpecialRule label ('ExtractFields field)
type InjectID label mn idn =
SpecialRule label ('InjectID mn idn)
class PerformAction (action :: SpecialRuleAction) where
runAction :: Proxy action -> Value -> Parser Value
instance Reifies d Value => PerformAction ('IfNoneThen d) where
runAction :: Proxy ('IfNoneThen d) -> Value -> Parser Value
runAction _ Null = Value -> Parser Value
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Value -> Parser Value) -> Value -> Parser Value
forall a b. (a -> b) -> a -> b
$ Proxy d -> Value
forall k (s :: k) a (proxy :: k -> *). Reifies s a => proxy s -> a
reflect @d Proxy d
forall k (t :: k). Proxy t
Proxy
runAction _ x :: Value
x = Value -> Parser Value
forall (f :: * -> *) a. Applicative f => a -> f a
pure Value
x
instance (KnownSymbol field) => PerformAction ('ExtractField field) where
runAction :: Proxy ('ExtractField field) -> Value -> Parser Value
runAction _ Null = Value -> Parser Value
forall (f :: * -> *) a. Applicative f => a -> f a
pure Value
Null
runAction _ o :: Value
o = String -> (Object -> Parser Value) -> Value -> Parser Value
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject (("extracting field " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Proxy field -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @field Proxy field
forall k (t :: k). Proxy t
Proxy) Text -> Getting String Text String -> String
forall s a. s -> Getting a s a -> a
^. Getting String Text String
Iso' Text String
unpacked)
(Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.: Proxy field -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @field Proxy field
forall k (t :: k). Proxy t
Proxy) Value
o
instance (KnownSymbol field) => PerformAction ('ExtractFields field) where
runAction :: Proxy ('ExtractFields field) -> Value -> Parser Value
runAction _ Null = Value -> Parser Value
forall (f :: * -> *) a. Applicative f => a -> f a
pure Value
Null
runAction _ o :: Value
o = String -> (Array -> Parser Value) -> Value -> Parser Value
forall a. String -> (Array -> Parser a) -> Value -> Parser a
withArray (("extracting fields " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Proxy field -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @field Proxy field
forall k (t :: k). Proxy t
Proxy) Text -> Getting String Text String -> String
forall s a. s -> Getting a s a -> a
^. Getting String Text String
Iso' Text String
unpacked)
((Array -> Value
Array (Array -> Value) -> Parser Array -> Parser Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) (Parser Array -> Parser Value)
-> (Array -> Parser Array) -> Array -> Parser Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Value -> Parser Value) -> Array -> Parser Array
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse (String -> (Object -> Parser Value) -> Value -> Parser Value
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject "extracting field" (Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.: Proxy field -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @field Proxy field
forall k (t :: k). Proxy t
Proxy))) Value
o
instance (KnownSymbol idn, KnownSymbol mn) => PerformAction ('InjectID idn mn) where
runAction :: Proxy ('InjectID idn mn) -> Value -> Parser Value
runAction _ = String -> (Object -> Parser Value) -> Value -> Parser Value
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject
(("injecting id from " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Proxy idn -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @idn Proxy idn
forall k (t :: k). Proxy t
Proxy Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> " into " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Proxy mn -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @mn Proxy mn
forall k (t :: k). Proxy t
Proxy) Text -> Getting String Text String -> String
forall s a. s -> Getting a s a -> a
^. Getting String Text String
Iso' Text String
unpacked) ((Object -> Parser Value) -> Value -> Parser Value)
-> (Object -> Parser Value) -> Value -> Parser Value
forall a b. (a -> b) -> a -> b
$ \o :: Object
o -> do
Value
id <- Object
o Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.: "id"
Value -> Parser Value
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Object -> Value
Object Object
o
Value -> (Value -> Value) -> Value
forall a b. a -> (a -> b) -> b
& Text -> Traversal' Value Value
forall t. AsValue t => Text -> Traversal' t Value
key (Proxy mn -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @mn Proxy mn
forall k (t :: k). Proxy t
Proxy) ((Value -> Identity Value) -> Value -> Identity Value)
-> ((Maybe Value -> Identity (Maybe Value))
-> Value -> Identity Value)
-> (Maybe Value -> Identity (Maybe Value))
-> Value
-> Identity Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Value -> Identity Value) -> Value -> Identity Value
forall t. AsValue t => IndexedTraversal' Int t Value
values ((Value -> Identity Value) -> Value -> Identity Value)
-> ((Maybe Value -> Identity (Maybe Value))
-> Value -> Identity Value)
-> (Maybe Value -> Identity (Maybe Value))
-> Value
-> Identity Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Object -> Identity Object) -> Value -> Identity Value
forall t. AsValue t => Prism' t Object
_Object ((Object -> Identity Object) -> Value -> Identity Value)
-> ((Maybe Value -> Identity (Maybe Value))
-> Object -> Identity Object)
-> (Maybe Value -> Identity (Maybe Value))
-> Value
-> Identity Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Index Object -> Lens' Object (Maybe (IxValue Object))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at (Proxy idn -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @idn Proxy idn
forall k (t :: k). Proxy t
Proxy) ((Maybe Value -> Identity (Maybe Value))
-> Value -> Identity Value)
-> Value -> Value -> Value
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Value
id)
type family FoldSpecialCases (rules :: [Type]) :: SpecialCaseList where
FoldSpecialCases '[] = 'SpecialCaseNil
FoldSpecialCases (SpecialRule label action ': xs) = 'SpecialCaseElem label action (FoldSpecialCases xs)
FoldSpecialCases _ = TL.TypeError ('TL.Text "What did you do?")
newtype WithSpecialCasesInner (rules :: SpecialCaseList) a = WithSpecialCasesInner
{ WithSpecialCasesInner rules a -> a
unwrapWithSpecialCases :: a
}
type family WithSpecialCases rules a :: Type where
WithSpecialCases rules a = WithSpecialCasesInner (FoldSpecialCases rules) a
class RunSpecialCase a where
runSpecialCases :: Proxy a -> Object -> Parser Object
instance RunSpecialCase 'SpecialCaseNil where
runSpecialCases :: Proxy 'SpecialCaseNil -> Object -> Parser Object
runSpecialCases _ = Object -> Parser Object
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Object -> Parser Object)
-> (Object -> Object) -> Object -> Parser Object
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Object -> Object
forall a. a -> a
id
instance (RunSpecialCase inner, KnownSymbol label, PerformAction action)
=> RunSpecialCase ('SpecialCaseElem label action inner) where
runSpecialCases :: Proxy ('SpecialCaseElem label action inner)
-> Object -> Parser Object
runSpecialCases _ o :: Object
o = do
Object
o' <- Proxy inner -> Object -> Parser Object
forall k (a :: k).
RunSpecialCase a =>
Proxy a -> Object -> Parser Object
runSpecialCases (Proxy inner
forall k (t :: k). Proxy t
Proxy @inner) Object
o
Value
v <- Object
o' Object -> Text -> Parser (Maybe Value)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Proxy label -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @label Proxy label
forall k (t :: k). Proxy t
Proxy Parser (Maybe Value) -> Value -> Parser Value
forall a. Parser (Maybe a) -> a -> Parser a
.!= Value
Null
Value
v' <- Proxy action -> Value -> Parser Value
forall (action :: SpecialRuleAction).
PerformAction action =>
Proxy action -> Value -> Parser Value
runAction (Proxy action
forall k (t :: k). Proxy t
Proxy @action) Value
v
Object -> Parser Object
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Object
o' Object -> (Object -> Object) -> Object
forall a b. a -> (a -> b) -> b
& Index Object -> Lens' Object (Maybe (IxValue Object))
forall m. At m => Index m -> Lens' m (Maybe (IxValue m))
at (Proxy label -> Text
forall (n :: Symbol). KnownSymbol n => Proxy n -> Text
textSymbolVal @label Proxy label
forall k (t :: k). Proxy t
Proxy) ((Maybe Value -> Identity (Maybe Value))
-> Object -> Identity Object)
-> Value -> Object -> Object
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Value
v')
instance (RunSpecialCase rules, Typeable a, Generic a, GFromJSON Zero (Rep a))
=> FromJSON (WithSpecialCasesInner rules a) where
parseJSON :: Value -> Parser (WithSpecialCasesInner rules a)
parseJSON = String
-> (Object -> Parser (WithSpecialCasesInner rules a))
-> Value
-> Parser (WithSpecialCasesInner rules a)
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject (TypeRep -> String
forall a. Show a => a -> String
show (TypeRep -> String) -> (Proxy a -> TypeRep) -> Proxy a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Proxy a -> TypeRep
forall k (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy a -> String) -> Proxy a -> String
forall a b. (a -> b) -> a -> b
$ Proxy a
forall k (t :: k). Proxy t
Proxy @a) ((Object -> Parser (WithSpecialCasesInner rules a))
-> Value -> Parser (WithSpecialCasesInner rules a))
-> (Object -> Parser (WithSpecialCasesInner rules a))
-> Value
-> Parser (WithSpecialCasesInner rules a)
forall a b. (a -> b) -> a -> b
$ \o :: Object
o -> do
Object
o' <- Proxy rules -> Object -> Parser Object
forall k (a :: k).
RunSpecialCase a =>
Proxy a -> Object -> Parser Object
runSpecialCases (Proxy rules
forall k (t :: k). Proxy t
Proxy @rules) Object
o
a -> WithSpecialCasesInner rules a
forall (rules :: SpecialCaseList) a.
a -> WithSpecialCasesInner rules a
WithSpecialCasesInner (a -> WithSpecialCasesInner rules a)
-> Parser a -> Parser (WithSpecialCasesInner rules a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Options -> Value -> Parser a
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON Options
jsonOptions (Object -> Value
Object Object
o')
data DefaultToEmptyArray
instance Reifies DefaultToEmptyArray Value where
reflect :: proxy DefaultToEmptyArray -> Value
reflect _ = Array -> Value
Array Array
forall a. Monoid a => a
mempty
data DefaultToZero
instance Reifies DefaultToZero Value where
reflect :: proxy DefaultToZero -> Value
reflect _ = Scientific -> Value
Number 0
data DefaultToFalse
instance Reifies DefaultToFalse Value where
reflect :: proxy DefaultToFalse -> Value
reflect _ = Bool -> Value
Bool Bool
False
newtype CalamityJSON a = CalamityJSON
{ CalamityJSON a -> a
unCalamityJSON :: a
}
instance (Typeable a, Generic a, GToJSON Zero (Rep a), GToEncoding Zero (Rep a)) => ToJSON (CalamityJSON a) where
toJSON :: CalamityJSON a -> Value
toJSON = Options -> a -> Value
forall a.
(Generic a, GToJSON Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON Options
jsonOptions (a -> Value) -> (CalamityJSON a -> a) -> CalamityJSON a -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CalamityJSON a -> a
forall a. CalamityJSON a -> a
unCalamityJSON
toEncoding :: CalamityJSON a -> Encoding
toEncoding = Options -> a -> Encoding
forall a.
(Generic a, GToJSON Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
jsonOptions (a -> Encoding)
-> (CalamityJSON a -> a) -> CalamityJSON a -> Encoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CalamityJSON a -> a
forall a. CalamityJSON a -> a
unCalamityJSON
instance (Typeable a, Generic a, GFromJSON Zero (Rep a)) => FromJSON (CalamityJSON a) where
parseJSON :: Value -> Parser (CalamityJSON a)
parseJSON = (a -> CalamityJSON a) -> Parser a -> Parser (CalamityJSON a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> CalamityJSON a
forall a. a -> CalamityJSON a
CalamityJSON (Parser a -> Parser (CalamityJSON a))
-> (Value -> Parser a) -> Value -> Parser (CalamityJSON a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Options -> Value -> Parser a
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON Options
jsonOptions
jsonOptions :: Options
jsonOptions :: Options
jsonOptions = Options
defaultOptions { sumEncoding :: SumEncoding
sumEncoding = SumEncoding
UntaggedValue
, fieldLabelModifier :: String -> String
fieldLabelModifier = Char -> String -> String
camelTo2 '_' (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '_')
, omitNothingFields :: Bool
omitNothingFields = Bool
True }
jsonOptionsKeepNothing :: Options
jsonOptionsKeepNothing :: Options
jsonOptionsKeepNothing = Options
defaultOptions { sumEncoding :: SumEncoding
sumEncoding = SumEncoding
UntaggedValue
, fieldLabelModifier :: String -> String
fieldLabelModifier = Char -> String -> String
camelTo2 '_' (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '_')
, omitNothingFields :: Bool
omitNothingFields = Bool
False }