1module Data.Schematic.Validation where
4import Control.Monad.Validation
6import Data.Functor.Identity
8import Data.Schematic.Path
9import Data.Schematic.Schema
10import Data.Schematic.Utils ()
12import Data.Singletons.Prelude
13import Data.Singletons.TypeLits
15import Data.Traversable
16import Data.Vector as V
22type Validation a = ValidationT ErrorMap Identity a
24type ErrorMap = MonoidMap Text [Text]
28 | DecodingError Text -- static
29 | ValidationError ErrorMap -- runtime
30 deriving (Show, Eq, Functor, Foldable, Traversable)
32isValid :: ParseResult a -> Bool
33isValid (Valid _) = True
36isDecodingError :: ParseResult a -> Bool
37isDecodingError (DecodingError _) = True
38isDecodingError _ = False
40isValidationError :: ParseResult a -> Bool
41isValidationError (ValidationError _) = True
42isValidationError _ = False
47 -> Sing (tcs :: TextConstraint)
49validateTextConstraint (JSONPath path) t = \case
52 nlen = withKnownNat n $ natVal n
53 predicate = nlen == (fromIntegral $ T.length t)
54 errMsg = "length of " <> path <> " should be == " <> T.pack (show nlen)
55 warn = vWarning $ mmSingleton path (pure errMsg)
59 nlen = withKnownNat n $ natVal n
60 predicate = nlen < (fromIntegral $ T.length t)
61 errMsg = "length of " <> path <> " should be < " <> T.pack (show nlen)
62 warn = vWarning $ mmSingleton path (pure errMsg)
66 nlen = withKnownNat n $ natVal n
67 predicate = nlen <= (fromIntegral $ T.length t)
68 errMsg = "length of " <> path <> " should be <= " <> T.pack (show nlen)
69 warn = vWarning $ mmSingleton path (pure errMsg)
73 nlen = withKnownNat n $ natVal n
74 predicate = nlen > (fromIntegral $ T.length t)
75 errMsg = "length of " <> path <> " should be > " <> T.pack (show nlen)
76 warn = vWarning $ mmSingleton path (pure errMsg)
80 nlen = withKnownNat n $ natVal n
81 predicate = nlen >= (fromIntegral $ T.length t)
82 errMsg = "length of " <> path <> " should be >= " <> T.pack (show nlen)
83 warn = vWarning $ mmSingleton path (pure errMsg)
87 regex = withKnownSymbol r $ symbolVal r
88 predicate = maybe False (const True) $ matchRegex (mkRegex regex) (T.unpack t)
89 errMsg = path <> " must match " <> T.pack (show regex)
90 warn = vWarning $ mmSingleton path (pure errMsg)
94 matching :: Sing (s :: [Symbol]) -> Bool
96 matching (SCons s@SSym fs) = T.pack (symbolVal s) == t || matching fs
97 errMsg = path <> " must be one of " <> T.pack (show (fromSing ss))
98 warn = vWarning $ mmSingleton path (pure errMsg)
99 unless (matching ss) warn
101validateNumberConstraint
104 -> Sing (tcs :: NumberConstraint)
106validateNumberConstraint (JSONPath path) num = \case
109 nlen = withKnownNat n $ natVal n
110 predicate = fromIntegral nlen == num
111 errMsg = path <> " should be == " <> T.pack (show nlen)
112 warn = vWarning $ mmSingleton path (pure errMsg)
113 unless predicate warn
116 nlen = withKnownNat n $ natVal n
117 predicate = num > fromIntegral nlen
118 errMsg = path <> " should be > " <> T.pack (show nlen)
119 warn = vWarning $ mmSingleton path (pure errMsg)
120 unless predicate warn
123 nlen = withKnownNat n $ natVal n
124 predicate = num >= fromIntegral nlen
125 errMsg = path <> " should be >= " <> T.pack (show nlen)
126 warn = vWarning $ mmSingleton path (pure errMsg)
127 unless predicate warn
130 nlen = withKnownNat n $ natVal n
131 predicate = fromIntegral nlen < num
132 errMsg = path <> " should be < " <> T.pack (show nlen)
133 warn = vWarning $ mmSingleton path (pure errMsg)
134 unless predicate warn
137 nlen = withKnownNat n $ natVal n
138 predicate = fromIntegral nlen <= num
139 errMsg = path <> " should be <= " <> T.pack (show nlen)
140 warn = vWarning $ mmSingleton path (pure errMsg)
141 unless predicate warn
143validateArrayConstraint
146 -> Sing (tcs :: ArrayConstraint)
148validateArrayConstraint (JSONPath path) v = \case
151 nlen = withKnownNat n $ natVal n
152 predicate = nlen == fromIntegral (V.length v)
153 errMsg = "length of " <> path <> " should be == " <> T.pack (show nlen)
154 warn = vWarning $ mmSingleton path (pure errMsg)
155 unless predicate warn
159 -> [DemotedPathSegment]
162validateJsonRepr sschema dpath jr = case jr of
163 ReprText t -> case sschema of
164 SSchemaText scs -> do
166 process :: Sing (cs :: [TextConstraint]) -> Validation ()
167 process SNil = pure ()
168 process (SCons c cs) = do
169 validateTextConstraint (demotedPathToText dpath) t c
172 ReprNumber n -> case sschema of
173 SSchemaNumber scs -> do
175 process :: Sing (cs :: [NumberConstraint]) -> Validation ()
176 process SNil = pure ()
177 process (SCons c cs) = do
178 validateNumberConstraint (demotedPathToText dpath) n c
182 ReprBoolean _ -> pure ()
183 ReprArray v -> case sschema of
184 SSchemaArray acs s -> do
186 process :: Sing (cs :: [ArrayConstraint]) -> Validation ()
187 process SNil = pure ()
188 process (SCons c cs) = do
189 validateArrayConstraint (demotedPathToText dpath) v c
192 for_ (V.indexed v) $ \(ix, jr') -> do
193 let newPath = dpath <> pure (DIx $ fromIntegral ix)
194 validateJsonRepr s newPath jr'
195 ReprOptional d -> case sschema of
196 SSchemaOptional ss -> case d of
197 Just x -> validateJsonRepr ss dpath x
199 ReprObject fs -> case sschema of
200 SSchemaObject _ -> go fs
202 go :: Rec FieldRepr (ts :: [ (Symbol, Schema) ] ) -> Validation ()
204 go (f@(FieldRepr d) :& ftl) = do
205 let newPath = dpath <> [DKey (knownFieldName f)]
206 validateJsonRepr (knownFieldSchema f) newPath d
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list