{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UnicodeSyntax #-}
module MatrixBot.AesonUtils where
import GHC.Generics
import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Char
import Data.Function
import Data.Typeable
import Control.Category ((>>>))
myGenericToJSON ∷ ∀a. (Generic a, Typeable a, GToJSON' Value Zero (Rep a)) ⇒ a → Value
myGenericToJSON :: forall a.
(Generic a, Typeable a, GToJSON' Value Zero (Rep a)) =>
a -> Value
myGenericToJSON
= Options -> a -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
genericToJSON
(Options -> a -> Value) -> Options -> a -> Value
forall a b. (a -> b) -> a -> b
$ Options
defaultOptions
Options -> (Options -> Options) -> Options
forall a b. a -> (a -> b) -> b
& forall a. Typeable a => Proxy a -> Options -> Options
cutTypeNamePrefix @a Proxy a
forall {k} (t :: k). Proxy t
Proxy
Options -> (Options -> Options) -> Options
forall a b. a -> (a -> b) -> b
& Options -> Options
camelCaseToSnakeCase
myGenericParseJSON ∷ ∀a. (Generic a, Typeable a, GFromJSON Zero (Rep a)) ⇒ Value → Parser a
myGenericParseJSON :: forall a.
(Generic a, Typeable a, GFromJSON Zero (Rep a)) =>
Value -> Parser a
myGenericParseJSON
= Options -> Value -> Parser a
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON
(Options -> Value -> Parser a) -> Options -> Value -> Parser a
forall a b. (a -> b) -> a -> b
$ Options
defaultOptions
Options -> (Options -> Options) -> Options
forall a b. a -> (a -> b) -> b
& forall a. Typeable a => Proxy a -> Options -> Options
cutTypeNamePrefix @a Proxy a
forall {k} (t :: k). Proxy t
Proxy
Options -> (Options -> Options) -> Options
forall a b. a -> (a -> b) -> b
& Options -> Options
camelCaseToSnakeCase
cutTypeNamePrefix ∷ ∀a. Typeable a ⇒ Proxy a → Options → Options
cutTypeNamePrefix :: forall a. Typeable a => Proxy a -> Options -> Options
cutTypeNamePrefix Proxy a
Proxy Options
opts = Options
opts
{ fieldLabelModifier = fieldLabelModifier opts >>> \String
x →
let
typeNamePrefix :: String
typeNamePrefix
= String -> String
cutTypeParams
(String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ case 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
$ forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @a of
Char
a : String
as → Char -> Char
toLower Char
a Char -> String -> String
forall a. a -> [a] -> [a]
: String
as
String
a → String
a
cutTypeParams :: String -> String
cutTypeParams String
"" = String
""
cutTypeParams (Char
' ' : String
_) = String
""
cutTypeParams (Char
c : String
cs) = Char
c Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
cutTypeParams String
cs
in
case Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
typeNamePrefix) String
x of
(String
a, Char
b : String
bs) | String
a String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
typeNamePrefix → Char -> Char
toLower Char
b Char -> String -> String
forall a. a -> [a] -> [a]
: String
bs
(String, String)
_ → String
x
}
camelCaseToSnakeCase ∷ Options → Options
camelCaseToSnakeCase :: Options -> Options
camelCaseToSnakeCase Options
opts = Options
opts
{ fieldLabelModifier = (fieldLabelModifier opts >>>) $ foldMap $ \case
Char
c | Char -> Bool
isUpper Char
c → [Char
'_', Char -> Char
toLower Char
c]
| Bool
otherwise → Char -> String
forall a. a -> [a]
forall (f :: * -> *) a. Applicative f => a -> f a
pure Char
c
}