{-# LANGUAGE AllowAmbiguousTypes #-} module Data.Schematic.DSL where import Data.Kind import Data.Schematic.Lens import Data.Schematic.Schema import Data.Scientific import Data.Singletons import Data.Singletons.Prelude hiding ((:.)) import Data.Singletons.TypeLits import Data.Tagged import Data.Text as T import Data.Union import qualified Data.Vector as V import Data.Vinyl import Data.Vinyl.Functor type Constructor a = forall fields b. (fields ~ FieldsOf a, FSubset fields b (FImage fields b)) => Rec (Tagged fields :. FieldRepr) b -> JsonRepr ('SchemaObject fields) withRepr :: Constructor a withRepr = ReprObject . rmap (unTagged . getCompose) . fcast class Representable s where constructField :: Sing fn -> Proxy s -> Repr s -> FieldRepr '(fn, s) instance SingI so => Representable ('SchemaObject so) where constructField sfn _ o = withKnownSymbol sfn $ FieldRepr $ ReprObject o instance (SingI cs, SingI sa) => Representable ('SchemaArray cs sa) where constructField sfn _ a = withKnownSymbol sfn $ FieldRepr $ ReprArray a instance SingI cs => Representable ('SchemaText cs) where constructField sfn _ t = withKnownSymbol sfn $ FieldRepr $ ReprText t instance SingI cs => Representable ('SchemaNumber cs) where constructField sfn _ n = withKnownSymbol sfn $ FieldRepr $ ReprNumber n instance Representable 'SchemaBoolean where constructField sfn _ b = withKnownSymbol sfn $ FieldRepr $ ReprBoolean b instance SingI so => Representable ('SchemaOptional so) where constructField sfn _ o = withKnownSymbol sfn $ FieldRepr $ ReprOptional o instance SingI (h ': tl) => Representable ('SchemaUnion (h ': tl)) where constructField sfn _ u = withKnownSymbol sfn $ FieldRepr $ ReprUnion u construct :: Sing s -> Repr s -> JsonRepr s construct s r = case s of SSchemaObject _ -> ReprObject r SSchemaArray _ _ -> ReprArray r SSchemaText _ -> ReprText r SSchemaNumber _ -> ReprNumber r SSchemaBoolean -> ReprBoolean r SSchemaOptional _ -> ReprOptional r SSchemaNull -> ReprNull SSchemaUnion ss -> case ss of SNil -> error "unconstructable union" SCons _ _ -> ReprUnion r type family FieldsOf (s :: Schema) :: [(Symbol, Schema)] where FieldsOf ('SchemaObject fs) = fs type FieldConstructor fn = forall byField fs. (byField ~ ByField fn fs (FIndex fn fs), Representable byField) => Repr byField -> (Tagged fs :. FieldRepr) '(fn, byField) field :: forall fn. KnownSymbol fn => FieldConstructor fn field = Compose . Tagged . constructField (sing :: Sing fn) Proxy type family Repr (s :: Schema) = (ty :: Type) where Repr ('SchemaObject so) = Rec FieldRepr so Repr ('SchemaArray cs sa) = V.Vector (JsonRepr sa) Repr ('SchemaText cs) = Text Repr ('SchemaNumber cs) = Scientific Repr 'SchemaBoolean = Bool Repr ('SchemaOptional so) = Maybe (JsonRepr so) Repr ('SchemaUnion (h ': tl)) = Union JsonRepr (h ': tl)