@@ -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
@@ -49,51 +50,51 @@ isValidationError (ValidationError _) = True
49isValidationError _ = False
50isValidationError _ = False
51validateTextConstraint
52validateTextConstraint
52− :: JSONPath
53+ :: JSONPathText
54 -> Sing (tcs :: TextConstraint)
55 -> Sing (tcs :: TextConstraint)
55 -> Validation ()
56 -> Validation ()
56−validateTextConstraint (JSONPath path) t = \case
57+validateTextConstraint (JSONPathText path) t = \case
57 STEq n -> do
58 STEq n -> do
59 nlen = withKnownNat n $ natVal n
60 nlen = withKnownNat n $ natVal n
60 predicate = nlen == (fromIntegral $ T.length t)
61 predicate = nlen == (fromIntegral $ T.length t)
61− errMsg = "length of " <> path <> " should be == " <> T.pack (show nlen)
62+ errMsg = "length should be == " <> T.pack (show nlen)
62 warn = vWarning $ mmSingleton path (pure errMsg)
63 warn = vWarning $ mmSingleton path (pure errMsg)
63 unless predicate warn
64 unless predicate warn
64 STLt n -> do
65 STLt n -> do
66 nlen = withKnownNat n $ natVal n
67 nlen = withKnownNat n $ natVal n
67 predicate = nlen > (fromIntegral $ T.length t)
68 predicate = nlen > (fromIntegral $ T.length t)
68− errMsg = "length of " <> path <> " should be < " <> T.pack (show nlen)
69+ errMsg = "length should be < " <> T.pack (show nlen)
69 warn = vWarning $ mmSingleton path (pure errMsg)
70 warn = vWarning $ mmSingleton path (pure errMsg)
70 unless predicate warn
71 unless predicate warn
71 STLe n -> do
72 STLe n -> do
73 nlen = withKnownNat n $ natVal n
74 nlen = withKnownNat n $ natVal n
74 predicate = nlen >= (fromIntegral $ T.length t)
75 predicate = nlen >= (fromIntegral $ T.length t)
75− errMsg = "length of " <> path <> " should be <= " <> T.pack (show nlen)
76+ errMsg = "length should be <= " <> T.pack (show nlen)
76 warn = vWarning $ mmSingleton path (pure errMsg)
77 warn = vWarning $ mmSingleton path (pure errMsg)
77 unless predicate warn
78 unless predicate warn
78 STGt n -> do
79 STGt n -> do
80 nlen = withKnownNat n $ natVal n
81 nlen = withKnownNat n $ natVal n
81 predicate = nlen < (fromIntegral $ T.length t)
82 predicate = nlen < (fromIntegral $ T.length t)
82− errMsg = "length of " <> path <> " should be > " <> T.pack (show nlen)
83+ errMsg = "length should be > " <> T.pack (show nlen)
83 warn = vWarning $ mmSingleton path (pure errMsg)
84 warn = vWarning $ mmSingleton path (pure errMsg)
84 unless predicate warn
85 unless predicate warn
85 STGe n -> do
86 STGe n -> do
87 nlen = withKnownNat n $ natVal n
88 nlen = withKnownNat n $ natVal n
88 predicate = nlen <= (fromIntegral $ T.length t)
89 predicate = nlen <= (fromIntegral $ T.length t)
89− errMsg = "length of " <> path <> " should be >= " <> T.pack (show nlen)
90+ errMsg = "length should be >= " <> T.pack (show nlen)
90 warn = vWarning $ mmSingleton path (pure errMsg)
91 warn = vWarning $ mmSingleton path (pure errMsg)
91 unless predicate warn
92 unless predicate warn
92 STRegex r -> do
93 STRegex r -> do
94 regex = withKnownSymbol r $ fromSing r
95 regex = withKnownSymbol r $ fromSing r
95 predicate = matchTest (makeRegex (T.unpack regex) :: Regex) (T.unpack t)
96 predicate = matchTest (makeRegex (T.unpack regex) :: Regex) (T.unpack t)
96− errMsg = path <> " must match " <> regex
97+ errMsg = "must match " <> regex
97 warn = vWarning $ mmSingleton path (pure errMsg)
98 warn = vWarning $ mmSingleton path (pure errMsg)
98 unless predicate warn
99 unless predicate warn
99 STEnum ss -> do
100 STEnum ss -> do
@@ -101,69 +102,97 @@ validateTextConstraint (JSONPath path) t = \case
101 matching :: Sing (s :: [Symbol]) -> Bool
102 matching :: Sing (s :: [Symbol]) -> Bool
102 matching SNil = False
103 matching SNil = False
103 matching (SCons s@SSym fs) = T.pack (symbolVal s) == t || matching fs
104 matching (SCons s@SSym fs) = T.pack (symbolVal s) == t || matching fs
104− errMsg = path <> " must be one of " <> T.pack (show (fromSing ss))
105+ errMsg = "must be one of " <> T.pack (show (fromSing ss))
105 warn = vWarning $ mmSingleton path (pure errMsg)
106 warn = vWarning $ mmSingleton path (pure errMsg)
106 unless (matching ss) warn
107 unless (matching ss) warn
108validateNumberConstraint
109validateNumberConstraint
109− :: JSONPath
110+ :: JSONPathText
110 -> Scientific
111 -> Scientific
111 -> Sing (tcs :: NumberConstraint)
112 -> Sing (tcs :: NumberConstraint)
112 -> Validation ()
113 -> Validation ()
113−validateNumberConstraint (JSONPath path) num = \case
114+validateNumberConstraint (JSONPathText path) num = \case
114 SNEq n -> do
115 SNEq n -> do
116 nlen = withKnownNat n $ natVal n
117 nlen = withKnownNat n $ natVal n
117 predicate = fromIntegral nlen == num
118 predicate = fromIntegral nlen == num
118− errMsg = path <> " should be == " <> T.pack (show nlen)
119+ errMsg = "should be == " <> T.pack (show nlen)
119 warn = vWarning $ mmSingleton path (pure errMsg)
120 warn = vWarning $ mmSingleton path (pure errMsg)
120 unless predicate warn
121 unless predicate warn
121 SNGt n -> do
122 SNGt n -> do
123 nlen = withKnownNat n $ natVal n
124 nlen = withKnownNat n $ natVal n
124 predicate = num > fromIntegral nlen
125 predicate = num > fromIntegral nlen
125− errMsg = path <> " should be > " <> T.pack (show nlen)
126+ errMsg = "should be > " <> T.pack (show nlen)
126 warn = vWarning $ mmSingleton path (pure errMsg)
127 warn = vWarning $ mmSingleton path (pure errMsg)
127 unless predicate warn
128 unless predicate warn
128 SNGe n -> do
129 SNGe n -> do
130 nlen = withKnownNat n $ natVal n
131 nlen = withKnownNat n $ natVal n
131 predicate = num >= fromIntegral nlen
132 predicate = num >= fromIntegral nlen
132− errMsg = path <> " should be >= " <> T.pack (show nlen)
133+ errMsg = "should be >= " <> T.pack (show nlen)
133 warn = vWarning $ mmSingleton path (pure errMsg)
134 warn = vWarning $ mmSingleton path (pure errMsg)
134 unless predicate warn
135 unless predicate warn
135 SNLt n -> do
136 SNLt n -> do
137 nlen = withKnownNat n $ natVal n
138 nlen = withKnownNat n $ natVal n
138 predicate = num < fromIntegral nlen
139 predicate = num < fromIntegral nlen
139− errMsg = path <> " should be < " <> T.pack (show nlen)
140+ errMsg = "should be < " <> T.pack (show nlen)
140 warn = vWarning $ mmSingleton path (pure errMsg)
141 warn = vWarning $ mmSingleton path (pure errMsg)
141 unless predicate warn
142 unless predicate warn
142 SNLe n -> do
143 SNLe n -> do
144 nlen = withKnownNat n $ natVal n
145 nlen = withKnownNat n $ natVal n
145 predicate = num <= fromIntegral nlen
146 predicate = num <= fromIntegral nlen
146− errMsg = path <> " should be <= " <> T.pack (show nlen)
147+ errMsg = "should be <= " <> T.pack (show nlen)
147 warn = vWarning $ mmSingleton path (pure errMsg)
148 warn = vWarning $ mmSingleton path (pure errMsg)
148 unless predicate warn
149 unless predicate warn
150validateArrayConstraint
151validateArrayConstraint
151− :: JSONPath
152+ :: JSONPathText
152 -> V.Vector a
153 -> V.Vector a
153 -> Sing (tcs :: ArrayConstraint)
154 -> Sing (tcs :: ArrayConstraint)
154 -> Validation ()
155 -> Validation ()
155−validateArrayConstraint (JSONPath path) v = \case
156+validateArrayConstraint (JSONPathText path) v = \case
156 SAEq n -> do
157 SAEq n -> do
158 nlen = withKnownNat n $ natVal n
159 nlen = withKnownNat n $ natVal n
159 predicate = nlen == fromIntegral (V.length v)
160 predicate = nlen == fromIntegral (V.length v)
160− errMsg = "length of " <> path <> " should be == " <> T.pack (show nlen)
161+ errMsg = "length should be == " <> T.pack (show nlen)
162+ warn = vWarning $ mmSingleton path (pure errMsg)
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)
161 warn = vWarning $ mmSingleton path (pure errMsg)
190 warn = vWarning $ mmSingleton path (pure errMsg)
162 unless predicate warn
191 unless predicate warn
164validateJsonRepr
193validateJsonRepr
165 :: Sing schema
194 :: Sing schema
166− -> [DemotedPathSegment]
195+ -> JSONPath
167 -> JsonRepr schema
196 -> JsonRepr schema
168 -> Validation ()
197 -> Validation ()
169validateJsonRepr sschema dpath jr = case jr of
198validateJsonRepr sschema dpath jr = case jr of
@@ -197,7 +226,7 @@ validateJsonRepr sschema dpath jr = case jr of
197 process cs
226 process cs
198 process acs
227 process acs
199 for_ (V.indexed v) $ \(ix, jr') -> do
228 for_ (V.indexed v) $ \(ix, jr') -> do
200− let newPath = dpath <> pure (DIx $ fromIntegral ix)
229+ let newPath = dpath <> pure (Index $ fromIntegral ix)
201 validateJsonRepr s newPath jr'
230 validateJsonRepr s newPath jr'
202 ReprOptional d -> case sschema of
231 ReprOptional d -> case sschema of
203 SSchemaOptional ss -> case d of
232 SSchemaOptional ss -> case d of
@@ -209,7 +238,7 @@ validateJsonRepr sschema dpath jr = case jr of
209 go :: Rec FieldRepr (ts :: [(Symbol, Schema)] ) -> Validation ()
238 go :: Rec FieldRepr (ts :: [(Symbol, Schema)] ) -> Validation ()
210 go RNil = pure ()
239 go RNil = pure ()
211 go (f@(FieldRepr d) :& ftl) = do
240 go (f@(FieldRepr d) :& ftl) = do
212− let newPath = dpath <> [DKey (knownFieldName f)]
241+ let newPath = dpath <> [Key (knownFieldName f)]
213 validateJsonRepr (knownFieldSchema f) newPath d
242 validateJsonRepr (knownFieldSchema f) newPath d
215 ReprUnion _ -> pure () -- FIXME
244 ReprUnion _ -> pure () -- FIXME
@@ -221,7 +250,7 @@ validateJsonRepr sschema dpath jr = case jr of
221 -- fail "impossible to produce subUnion, please report this as a bug"
250 -- fail "impossible to produce subUnion, please report this as a bug"
222 -- Just x -> do
251 -- Just x -> do
224− -- JSONPath path = demotedPathToText dpath
253+ -- JSONPathText path = demotedPathToText dpath
225 -- case stl of
254 -- case stl of
226 -- SNil -> void $ vWarning $ mmSingleton path
255 -- SNil -> void $ vWarning $ mmSingleton path
227 -- $ pure "union handling error, please report this as bug"
256 -- $ pure "union handling error, please report this as bug"