schema-0.0.3: src/Data/Schema/Builder.hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Data.Schema.Builder
( Builder (..)
, ToSchema (..)
, atom
) where
import Control.Applicative (liftA2)
import Data.Fix (Fix (..))
import Data.Schema.Type (Schema, SchemaF (..), Type (..), prodType)
import GHC.Generics
data Builder a = Builder
{ zero :: a
, getSchema :: Schema
}
deriving (Read, Show)
atom :: Type -> a -> Builder a
atom ty z = Builder z (Fix (Atom ty))
instance Semigroup (Builder a) where
Builder x l <> Builder _ r = Builder x (l <> r)
instance Functor Builder where
fmap f (Builder x s) = Builder (f x) s
instance Applicative Builder where
pure x = Builder x (Fix Empty)
Builder f l <*> Builder x r = Builder (f x) (prodType l r)
class GToSchema f where
gToSchema :: Builder (f a)
class ToSchema a where
toSchema :: Builder a
default toSchema :: (Generic a, GToSchema (Rep a)) => Builder a
toSchema = to <$> gToSchema
instance ToSchema a => ToSchema [a] where
toSchema = Builder [v] (Fix (List s))
where
Builder v s = toSchema
instance GToSchema U1 where
gToSchema = Builder U1 (Fix Empty)
instance (GToSchema a, GToSchema b) => GToSchema (a :*: b) where
gToSchema = liftA2 (:*:) gToSchema gToSchema
instance (GToSchema a, GToSchema b) => GToSchema (a :+: b) where
gToSchema = (L1 <$> gToSchema) <> (R1 <$> gToSchema)
instance (Datatype d, GToSchema f) => GToSchema (D1 d f) where
gToSchema =
M1 <$> addDatatypeName
(moduleName (undefined :: D1 d f a))
(datatypeName (undefined :: D1 d f a))
gToSchema
where
addDatatypeName :: String -> String -> Builder a -> Builder a
addDatatypeName mName dName (Builder x (Fix (Sum Nothing cs))) =
Builder x . Fix . Sum (Just (mName, dName)) $ cs
addDatatypeName _ _ s = s
instance (Constructor c, GToSchema f) => GToSchema (C1 c f) where
gToSchema = M1 <$> addConName (conName (undefined :: C1 c f a)) gToSchema
where
addConName :: String -> Builder a -> Builder a
addConName name (Builder x (Fix Empty)) =
Builder x . Fix . Atom . TyName $ name
addConName name (Builder x s) =
Builder x . Fix . Sum Nothing . (:[]) . Fix . Con name $ s
instance (Selector s, GToSchema f) => GToSchema (S1 s f) where
gToSchema = M1 <$> addSelName (selName (undefined :: S1 s f a)) gToSchema
where
addSelName :: String -> Builder a -> Builder a
addSelName "" b = b
addSelName name (Builder x s) = Builder x . Fix . Field name $ s
instance GToSchema a => GToSchema (M1 t c a) where
gToSchema = M1 <$> gToSchema
instance ToSchema a => GToSchema (K1 i a) where
gToSchema = K1 <$> toSchema