@@ -1,24 +1,32 @@
1{-# LANGUAGE AllowAmbiguousTypes #-}
1{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE OverloadedLists #-}
3+{-# LANGUAGE OverloadedStrings #-}
3module Data.Schematic.Validation where
5module Data.Schematic.Validation where
5import Control.Applicative
7import Control.Applicative
6import Control.Category ((<<<), (>>>))
8import Control.Category ((<<<), (>>>))
7import Data.Eq.Deriving (deriveEq1)
10import Data.Eq.Deriving (deriveEq1)
8import Data.Foldable as F
11import Data.Foldable as F
9import Data.Functor.Classes
12import Data.Functor.Classes
10import Data.Functor.Foldable
13import Data.Functor.Foldable
14+import Data.HashMap.Strict as H
11import Data.Kind
15import Data.Kind
12import Data.Maybe
16import Data.Maybe
17+import Data.Scientific
13import Data.Singletons.Decide
18import Data.Singletons.Decide
19+import Data.Singletons.Prelude.List
14import Data.Singletons.TH
20import Data.Singletons.TH
21+import Data.Singletons.TypeLits
15import Data.Text as T
22import Data.Text as T
23+import Data.Vector as V
16import Data.Vinyl hiding (Dict)
24import Data.Vinyl hiding (Dict)
17import Data.Vinyl.Functor
25import Data.Vinyl.Functor
18import Text.Show.Deriving (deriveShow1)
26import Text.Show.Deriving (deriveShow1)
21−-- | Type Tags
29+-- -- | Type Tags
@@ -29,52 +37,127 @@ data JType
30genSingletons [ ''JType ]
38genSingletons [ ''JType ]
32−instance Show (Sing JText) where showsPrec 4 _ = showString "SJText"
40+-- instance Show (Sing JText) where showsPrec 4 _ = showString "SJText"
33−instance Show (Sing JNumber) where showsPrec 4 _ = showString "SJNumber"
41+-- instance Show (Sing JNumber) where showsPrec 4 _ = showString "SJNumber"
34−instance Show (Sing JArray) where showsPrec 4 _ = showString "SJArray"
42+-- instance Show (Sing JArray) where showsPrec 4 _ = showString "SJArray"
35−instance Show (Sing JObject) where showsPrec 4 _ = showString "SJObject"
43+-- instance Show (Sing JObject) where showsPrec 4 _ = showString "SJObject"
36−instance Show (Sing JNull) where showsPrec 4 _ = showString "SJNull"
44+-- instance Show (Sing JNull) where showsPrec 4 _ = showString "SJNull"
38−instance Eq (Sing JText) where (==) _ _ = True
46+-- instance Eq (Sing JText) where (==) _ _ = True
39−instance Eq (Sing JNumber) where (==) _ _ = True
47+-- instance Eq (Sing JNumber) where (==) _ _ = True
40−instance Eq (Sing JArray) where (==) _ _ = True
48+-- instance Eq (Sing JArray) where (==) _ _ = True
41−instance Eq (Sing JObject) where (==) _ _ = True
49+-- instance Eq (Sing JObject) where (==) _ _ = True
42−instance Eq (Sing JNull) where (==) _ _ = True
50+-- instance Eq (Sing JNull) where (==) _ _ = True
44−type family CRepr (jty :: JType) :: Type where
52+type family CRepr (jty :: Schema) :: Type where
45− CRepr JText = TextConstraint
53+ CRepr (SchemaText cs) = TextConstraint
46− CRepr JNumber = NumberConstraint
54+ CRepr (SchemaNumber cs) = NumberConstraint
47− CRepr JObject = (String, Schema)
55+ CRepr (SchemaObject fs) = (String, Schema)
48− CRepr JArray = ArrayConstraint
56+ CRepr (SchemaArray ar s) = ArrayConstraint
50data TextConstraint
58data TextConstraint
51− = LengthEq Integer
59+ = TEq Nat
52− | LengthLe Integer
60+ | TLe Nat
53− | LengthGt Integer
61+ | TGt Nat
54− deriving (Show, Eq)
62+ | Regex Symbol
64+data instance Sing (tc :: TextConstraint) where
65+ STextLengthEq :: Sing n -> Sing (TEq n)
66+ STextLengthLe :: Sing n -> Sing (TLe n)
67+ STextLengthGt :: Sing n -> Sing (TGt n)
56data NumberConstraint
69data NumberConstraint
57− = Le Integer
70+ = NLe Nat
58− | Gt Integer
71+ | NGt Nat
59− | Eq Integer
72+ | NEq Nat
60− deriving (Show, Eq)
73+
74+data instance Sing (nc :: NumberConstraint) where
75+ SNumberEq :: Sing n -> Sing (NEq n)
76+ SNumberGt :: Sing n -> Sing (NGt n)
77+ SNumberLe :: Sing n -> Sing (NLe n)
62data ArrayConstraint
79data ArrayConstraint
63− = LengthArrEq Integer
80+ = AEq Nat
66−type ObjectConstraint s = [(String, s)]
82+data instance Sing (ac :: ArrayConstraint) where
83+ SArrayEq :: Sing n -> Sing (AEq n)
68−data SchemaF s
85+data Schema
69 = SchemaText [TextConstraint]
86 = SchemaText [TextConstraint]
70 | SchemaNumber [NumberConstraint]
87 | SchemaNumber [NumberConstraint]
71− | SchemaObject (ObjectConstraint s)
88+ | SchemaObject [(Symbol, Schema)]
72− | SchemaArray [ArrayConstraint] s
89+ | SchemaArray [ArrayConstraint] Schema
73 | SchemaNull
90 | SchemaNull
76−type Schema = Fix SchemaF
80−deriveShow1 ''SchemaF
92+data instance Sing (schema :: Schema) where
93+ SSchemaText :: Sing tcs -> Sing (SchemaText tcs)
94+ SSchemaNumber :: Sing ncs -> Sing (SchemaNumber ncs)
95+ SSchemaArray :: Sing acs -> Sing schema -> Sing (SchemaArray acs schema)
96+ SSchemaObject :: Sing fields -> Sing (SchemaObject fields)
97+ SSchemaNull :: Sing SchemaNull
99+type family MapSnd (l :: [(k, Schema)]) :: [Schema] where
101+ MapSnd ( '(f,s) ': tl) = s ': MapSnd tl
103+data FieldRepr :: (Symbol, Schema) -> Type where
104+ FieldRepr :: KnownSymbol name => JsonRepr schema -> FieldRepr '(name, schema)
106+data JsonRepr :: Schema -> Type where
107+ ReprText :: Text -> JsonRepr (SchemaText cs)
108+ ReprNumber :: Scientific -> JsonRepr (SchemaNumber cs)
109+ ReprNull :: JsonRepr SchemaNull
110+ ReprArray :: V.Vector (JsonRepr s) -> JsonRepr (SchemaArray cs s)
111+ ReprObject :: Rec FieldRepr fs -> JsonRepr (SchemaObject fs)
113+instance J.ToJSON (JsonRepr a) where
114+ toJSON (ReprText t) = J.String t
115+ toJSON ReprNull = J.Null
116+ toJSON (ReprNumber n) = J.Number n
117+ toJSON (ReprArray v) = J.Array $ toJSON <$> v
118+ toJSON (ReprObject r) = let
121+ . (KnownSymbol name)
122+ => FieldRepr '(name, s)
124+ extract (FieldRepr s) = (T.pack $ symbolVal $ Proxy @name, toJSON s)
125+ fold :: Rec FieldRepr fs -> [(Text, J.Value)]
128+ fr@(FieldRepr s) :& tl -> (extract fr) : fold tl
129+ in J.Object . H.fromList . fold $ r
133+ '[ '("foo", SchemaArray '[AEq 3] (SchemaNumber '[NGt 10]))
134+ , '("bar", SchemaText '[Regex "\\w+"])]
136+spec :: (SingKind Schema, SingI Spec) => DemoteRep Schema
137+spec = fromSing (sing :: Sing Spec)
139+exampleTest :: JsonRepr (SchemaText '[TEq 3])
140+exampleTest = ReprText "ololo"
142+exampleNumber :: JsonRepr (SchemaNumber '[NEq 3])
143+exampleNumber = ReprNumber 3
145+exampleArray :: JsonRepr (SchemaArray '[AEq 1] (SchemaNumber '[NEq 3]))
146+exampleArray = ReprArray [exampleNumber]
149+ :: JsonRepr (SchemaObject '[ '("foo", SchemaArray '[AEq 1] (SchemaNumber '[NEq 3]))] )
150+exampleObject = ReprObject $ FieldRepr exampleArray :& RNil
152+example :: JsonRepr Spec
153+example = ReprObject $
154+ FieldRepr (ReprArray [ReprNumber 3])
155+ :& FieldRepr (ReprText "test")
158+class FalseConstraint
160+type family TopLevel (spec :: Schema) :: Constraint where
161+ TopLevel (SchemaArray a e) = ()
162+ TopLevel (SchemaObject o) = ()
163+ TopLevel spec = FalseConstraint