@@ -3,6 +3,7 @@ module Data.Schematic.Validation where
3import Control.Monad
3import Control.Monad
4import Control.Monad.Validation
4import Control.Monad.Validation
5import Data.Aeson
5import Data.Aeson
6+import Data.Aeson.Internal
6import Data.Aeson.Types
7import Data.Aeson.Types
7import Data.Foldable
8import Data.Foldable
8import Data.Functor.Identity
9import Data.Functor.Identity
@@ -17,6 +18,7 @@ import Data.Traversable
17import Data.Union
18import Data.Union
18import Data.Vector as V
19import Data.Vector as V
19import Data.Vinyl
20import Data.Vinyl
21+import Data.Vinyl.TypeLevel
20import Prelude as P
22import Prelude as P
21import Text.Regex.TDFA
23import Text.Regex.TDFA
@@ -37,7 +39,7 @@ instance (TopLevel a, SingI a, FromJSON (JsonRepr a))
38isValid :: ParseResult a -> Bool
40isValid :: ParseResult a -> Bool
39isValid (Valid _) = True
41isValid (Valid _) = True
40−isValid _ = False
42+isValid _ = False
42isDecodingError :: ParseResult a -> Bool
44isDecodingError :: ParseResult a -> Bool
43isDecodingError (DecodingError _) = True
45isDecodingError (DecodingError _) = True
@@ -48,11 +50,11 @@ isValidationError (ValidationError _) = True
48isValidationError _ = False
50isValidationError _ = False
50validateTextConstraint
52validateTextConstraint
51− :: JSONPath
53+ :: JSONPathText
53 -> Sing (tcs :: TextConstraint)
55 -> Sing (tcs :: TextConstraint)
54 -> Validation ()
56 -> Validation ()
55−validateTextConstraint (JSONPath path) t = \case
57+validateTextConstraint (JSONPathText path) t = \case
56 STEq n -> do
58 STEq n -> do
58 nlen = withKnownNat n $ natVal n
60 nlen = withKnownNat n $ natVal n
@@ -105,11 +107,11 @@ validateTextConstraint (JSONPath path) t = \case
105 unless (matching ss) warn
107 unless (matching ss) warn
107validateNumberConstraint
109validateNumberConstraint
108− :: JSONPath
110+ :: JSONPathText
109 -> Scientific
111 -> Scientific
110 -> Sing (tcs :: NumberConstraint)
112 -> Sing (tcs :: NumberConstraint)
111 -> Validation ()
113 -> Validation ()
112−validateNumberConstraint (JSONPath path) num = \case
114+validateNumberConstraint (JSONPathText path) num = \case
113 SNEq n -> do
115 SNEq n -> do
115 nlen = withKnownNat n $ natVal n
117 nlen = withKnownNat n $ natVal n
@@ -147,11 +149,11 @@ validateNumberConstraint (JSONPath path) num = \case
147 unless predicate warn
149 unless predicate warn
149validateArrayConstraint
151validateArrayConstraint
150− :: JSONPath
152+ :: JSONPathText
151 -> V.Vector a
153 -> V.Vector a
152 -> Sing (tcs :: ArrayConstraint)
154 -> Sing (tcs :: ArrayConstraint)
153 -> Validation ()
155 -> Validation ()
154−validateArrayConstraint (JSONPath path) v = \case
156+validateArrayConstraint (JSONPathText path) v = \case
155 SAEq n -> do
157 SAEq n -> do
157 nlen = withKnownNat n $ natVal n
159 nlen = withKnownNat n $ natVal n
@@ -159,10 +161,38 @@ validateArrayConstraint (JSONPath path) v = \case
159 errMsg = "length should be == " <> T.pack (show nlen)
161 errMsg = "length should be == " <> T.pack (show nlen)
160 warn = vWarning $ mmSingleton path (pure errMsg)
162 warn = vWarning $ mmSingleton path (pure errMsg)
161 unless predicate warn
163 unless predicate warn
166+ nlen = withKnownNat n $ natVal n
167+ predicate = fromIntegral (V.length v) > nlen
168+ errMsg = "length should be > " <> T.pack (show nlen)
169+ warn = vWarning $ mmSingleton path (pure errMsg)
170+ unless predicate warn
173+ nlen = withKnownNat n $ natVal n
174+ predicate = fromIntegral (V.length v) >= nlen
175+ errMsg = "length should be >= " <> T.pack (show nlen)
176+ warn = vWarning $ mmSingleton path (pure errMsg)
177+ unless predicate warn
180+ nlen = withKnownNat n $ natVal n
181+ predicate = fromIntegral (V.length v) < nlen
182+ errMsg = "length should be < " <> T.pack (show nlen)
183+ warn = vWarning $ mmSingleton path (pure errMsg)
184+ unless predicate warn
187+ nlen = withKnownNat n $ natVal n
188+ predicate = fromIntegral (V.length v) <= nlen
189+ errMsg = "length should be <= " <> T.pack (show nlen)
190+ warn = vWarning $ mmSingleton path (pure errMsg)
191+ unless predicate warn
163validateJsonRepr
193validateJsonRepr
164 :: Sing schema
194 :: Sing schema
165− -> [DemotedPathSegment]
195+ -> JSONPath
166 -> JsonRepr schema
196 -> JsonRepr schema
167 -> Validation ()
197 -> Validation ()
168validateJsonRepr sschema dpath jr = case jr of
198validateJsonRepr sschema dpath jr = case jr of
@@ -196,7 +226,7 @@ validateJsonRepr sschema dpath jr = case jr of
196 process cs
226 process cs
197 process acs
227 process acs
198 for_ (V.indexed v) $ \(ix, jr') -> do
228 for_ (V.indexed v) $ \(ix, jr') -> do
199− let newPath = dpath <> pure (DIx $ fromIntegral ix)
229+ let newPath = dpath <> pure (Index $ fromIntegral ix)
200 validateJsonRepr s newPath jr'
230 validateJsonRepr s newPath jr'
201 ReprOptional d -> case sschema of
231 ReprOptional d -> case sschema of
202 SSchemaOptional ss -> case d of
232 SSchemaOptional ss -> case d of
@@ -208,17 +238,49 @@ validateJsonRepr sschema dpath jr = case jr of
208 go :: Rec FieldRepr (ts :: [(Symbol, Schema)] ) -> Validation ()
238 go :: Rec FieldRepr (ts :: [(Symbol, Schema)] ) -> Validation ()
209 go RNil = pure ()
239 go RNil = pure ()
210 go (f@(FieldRepr d) :& ftl) = do
240 go (f@(FieldRepr d) :& ftl) = do
211− let newPath = dpath <> [DKey (knownFieldName f)]
241+ let newPath = dpath <> [Key (knownFieldName f)]
212 validateJsonRepr (knownFieldSchema f) newPath d
242 validateJsonRepr (knownFieldSchema f) newPath d
244+ ReprUnion _ -> pure () -- FIXME
214− ReprUnion ru -> case sschema of
245+ -- case sschema of
215− SSchemaUnion su -> validateUnion su ru
246+ -- SSchemaUnion ss -> case ss of
216− where
247+ -- SCons s stl -> case umatch' s u of
217− validateUnion :: Sing us -> Union JsonRepr us -> Validation ()
248+ -- Nothing -> case urestrict u of
218− validateUnion ss r = case (ss,r) of
249+ -- Nothing ->
219− (SCons s _, This v) -> validateJsonRepr s dpath v
250+ -- fail "impossible to produce subUnion, please report this as a bug"
220− (SCons _ stl, That r') -> validateUnion stl r'
251+ -- Just x -> do
221− (SNil,_) -> fail "Invalid union. Please report this as a bug"
252+ -- let
253+ -- JSONPathText path = demotedPathToText dpath
255+ -- SNil -> void $ vWarning $ mmSingleton path
256+ -- $ pure "union handling error, please report this as bug"
258+ -- validateJsonRepr (SSchemaUnion (SCons s' stl')) dpath
259+ -- $ toUnion (SCons s' stl') x
260+ -- Just x -> validateJsonRepr s dpath x
263+-- :: Sing (s ': stl)
264+-- -> ( USubset stl (s ': stl) (RImage stl (s ': stl))
265+-- => Union f (s ': stl)
266+-- -> Maybe (Union f stl) )
267+-- subUnion (SCons s stl) = urestrict
270+-- :: Sing (s ': stl)
271+-- -> (USubset stl (s ': stl) (RImage stl (s ': stl)) => Maybe (Union f stl))
272+-- -> Maybe (Union f stl)
273+-- withUSubset (SCons s stl) r = r
276+ :: USubset s' (s ': ss) (RImage s' (s ': ss))
278+ -> Union JsonRepr s'
279+ -> JsonRepr ('SchemaUnion (s ': ss))
280+toUnion _ = ReprUnion . urelax
282+umatch' :: UElem a as i => Sing a -> Union f as -> Maybe (f a)
283+umatch' _ u = umatch u
223parseAndValidateJson
285parseAndValidateJson
224 :: forall schema
286 :: forall schema