diff --git a/schematic.cabal b/schematic.cabal index df00704..732266f 100644 --- a/schematic.cabal +++ b/schematic.cabal @@ -16,6 +16,7 @@ cabal-version: >=1.10 library exposed-modules: Data.Schematic , Data.Schematic.DSL + , Data.Schematic.Compat , Data.Schematic.Generator , Data.Schematic.Generator.Regex , Data.Schematic.Instances @@ -25,6 +26,7 @@ library , Data.Schematic.Migration , Data.Schematic.Path , Data.Schematic.Schema + , Data.Schematic.Constraints , Data.Schematic.Validation , Data.Schematic.Verifier , Data.Schematic.Verifier.Array @@ -65,7 +67,7 @@ library , TypeOperators , TypeSynonymInstances , UndecidableInstances - build-depends: base >=4.11 && <4.13 + build-depends: base >=4.10 && <4.13 , bytestring , aeson >= 1 , containers @@ -75,7 +77,7 @@ library , regex-tdfa , regex-tdfa-text , scientific - , singletons >= 2.4 + , singletons , smallcheck , tagged , template-haskell @@ -95,7 +97,7 @@ test-suite spec default-language: Haskell2010 build-depends: HUnit , aeson >= 1 - , base >=4.11 && <4.13 + , base >=4.10 && <4.13 , bytestring , containers , hjsonschema diff --git a/src/Data/Schematic.hs b/src/Data/Schematic.hs index eba608b..121e90e 100644 --- a/src/Data/Schematic.hs +++ b/src/Data/Schematic.hs @@ -7,6 +7,8 @@ module Data.Schematic , module Data.Schematic.Lens , module Data.Schematic.Migration , module Data.Schematic.Schema + , module Data.Schematic.Constraints + , module Data.Schematic.Compat , decodeAndValidateJson , parseAndValidateJson , parseAndValidateJsonBy @@ -27,6 +29,8 @@ import Data.Aeson as J import Data.Aeson.Types as J import Data.ByteString.Lazy as BL import Data.Functor.Identity as F +import Data.Schematic.Compat +import Data.Schematic.Constraints import Data.Schematic.DSL import Data.Schematic.Helpers import Data.Schematic.JsonSchema diff --git a/src/Data/Schematic/Compat.hs b/src/Data/Schematic/Compat.hs new file mode 100644 index 0000000..83d927f --- /dev/null +++ b/src/Data/Schematic/Compat.hs @@ -0,0 +1,28 @@ +{-# LANGUAGE CPP #-} +module Data.Schematic.Compat where + +import Data.Singletons.Prelude +import GHC.TypeLits +#if MIN_VERSION_base(4,12,0) +import Data.Vinyl +#else +import Data.Kind +#endif + + +type DeNat = Demote Nat +-- ^ Demote Nat is depends on version of singletons + +#if MIN_VERSION_singletons(2,4,0) +type (:++) a b = (++) a b +#endif + +#if MIN_VERSION_vinyl(0,9,0) +type RMapCompat fs = RMap fs +type ReifyConstraintCompat c repr fs = ReifyConstraint c repr fs +type RecordToListCompat fs = RecordToList fs +#else +type RMapCompat fs = (() :: Constraint) +type ReifyConstraintCompat c fs repr = (() :: Constraint) +type RecordToListCompat fs = (() :: Constraint) +#endif diff --git a/src/Data/Schematic/Constraints.hs b/src/Data/Schematic/Constraints.hs new file mode 100644 index 0000000..625f63f --- /dev/null +++ b/src/Data/Schematic/Constraints.hs @@ -0,0 +1,41 @@ +{-# LANGUAGE EmptyCase #-} +{-# OPTIONS_GHC -fprint-explicit-kinds #-} + +module Data.Schematic.Constraints where + +import Data.Schematic.Compat +import Data.Singletons.Prelude +import Data.Singletons.TH +import Data.Singletons.TypeLits +import Data.Text as T +import GHC.Generics (Generic) + + +singletons [d| + data TextConstraint' s n + = TEq n + | TLt n + | TLe n + | TGt n + | TGe n + | TRegex s + | TEnum [s] + deriving (Eq, Show, Generic) + + data NumberConstraint' n + = NLe n + | NLt n + | NGt n + | NGe n + | NEq n + deriving (Eq, Show, Generic) + + data ArrayConstraint' n = AEq n deriving (Eq, Show, Generic) + |] + +type TextConstraintT = TextConstraint' Text DeNat +type TextConstraint = TextConstraint' Symbol Nat +type NumberConstraintT = NumberConstraint' DeNat +type NumberConstraint = NumberConstraint' Nat +type ArrayConstraintT = ArrayConstraint' DeNat +type ArrayConstraint = ArrayConstraint' Nat diff --git a/src/Data/Schematic/DSL.hs b/src/Data/Schematic/DSL.hs index da16bfd..0ca1f09 100644 --- a/src/Data/Schematic/DSL.hs +++ b/src/Data/Schematic/DSL.hs @@ -1,9 +1,9 @@ {-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE CPP #-} module Data.Schematic.DSL where import Data.Kind +import Data.Schematic.Compat import Data.Schematic.Lens import Data.Schematic.Schema import Data.Scientific @@ -18,19 +18,12 @@ import Data.Vinyl import Data.Vinyl.Functor -#if MIN_VERSION_base(4,12,0) type Constructor a = forall fields b - . (fields ~ FieldsOf a, FSubset fields b (FImage fields b), RMap fields) + . (fields ~ FieldsOf a, FSubset fields b (FImage fields b), RMapCompat fields) => Rec (Tagged fields :. FieldRepr) b -> JsonRepr ('SchemaObject fields) -#else -type Constructor a - = forall fields b - . (fields ~ FieldsOf a, FSubset fields b (FImage fields b)) - => Rec (Tagged fields :. FieldRepr) b - -> JsonRepr ('SchemaObject fields) -#endif + withRepr :: Constructor a withRepr = ReprObject . rmap (unTagged . getCompose) . fcast diff --git a/src/Data/Schematic/Generator.hs b/src/Data/Schematic/Generator.hs index 59acde4..4d9d8b5 100644 --- a/src/Data/Schematic/Generator.hs +++ b/src/Data/Schematic/Generator.hs @@ -1,13 +1,14 @@ module Data.Schematic.Generator where -import Data.Maybe -import Data.Schematic.Generator.Regex -import {-# SOURCE #-} Data.Schematic.Schema -import Data.Schematic.Verifier -import Data.Scientific -import Data.Text (Text, pack) -import qualified Data.Vector as V -import Test.SmallCheck.Series +import Control.Applicative +import Data.Maybe +import Data.Schematic.Constraints +import Data.Schematic.Generator.Regex +import Data.Schematic.Verifier +import Data.Scientific +import Data.Text (Text, pack) +import Test.SmallCheck.Series + maxHigh :: Int maxHigh = 30 @@ -30,35 +31,18 @@ textLengthSeries = textEnumSeries :: Monad m => [Text] -> Series m Text textEnumSeries enum = generate $ \depth -> take depth enum -textSeries :: Monad m => [DemotedTextConstraint] -> Series m Text -textSeries cs = do - let mvcs = verifyTextConstraints cs - case mvcs of - Just vcs -> do - n <- textSeries' vcs - pure n - Nothing -> pure "error" +textSeries :: Monad m => [TextConstraintT] -> Series m Text +textSeries cs = maybe (pure "error") textSeries' $ verifyTextConstraints cs textSeries' :: Monad m => [VerifiedTextConstraint] -> Series m Text textSeries' [] = pure "sample" -textSeries' vcs = do - let enums = listToMaybe [x | VTEnum x <- vcs] - case enums of - Just e -> textEnumSeries e - Nothing -> do - let regexps = listToMaybe [x | VTRegex x _ _ <- vcs] - case regexps of - Just e -> regexSeries e - Nothing -> textLengthSeries vcs +textSeries' vcs + = fromMaybe (textLengthSeries vcs) + $ textEnumSeries <$> listToMaybe [x | VTEnum x <- vcs] + <|> regexSeries <$> listToMaybe [x | VTRegex x _ _ <- vcs] -numberSeries :: Monad m => [DemotedNumberConstraint] -> Series m Scientific -numberSeries cs = do - let mvcs = verifyNumberConstraints cs - case mvcs of - Just vcs -> do - n <- numberSeries' vcs - pure $ n - Nothing -> pure 0 +numberSeries :: Monad m => [NumberConstraintT] -> Series m Scientific +numberSeries cs = maybe (pure 0) numberSeries' $ verifyNumberConstraints cs numberSeries' :: Monad m => VerifiedNumberConstraint -> Series m Scientific numberSeries' = @@ -69,23 +53,3 @@ numberSeries' = h = fromMaybe maxHigh (fromIntegral <$> mh) - 1 n <- generate $ \depth -> take depth [l .. h] pure $ fromIntegral n - -arraySeries - :: (Monad m, Serial m (JsonRepr s)) - => [DemotedArrayConstraint] - -> Series m (V.Vector (JsonRepr s)) -arraySeries cs = do - let mvcs = verifyArrayConstraint cs - case mvcs of - Just vcs -> arraySeries' vcs - Nothing -> pure V.empty - -arraySeries' - :: forall m s. (Monad m, Serial m (JsonRepr s)) - => Maybe VerifiedArrayConstraint - -> Series m (V.Vector (JsonRepr s)) -arraySeries' ml = do - objs <- V.replicateM (maybe minRepeat f ml) (series :: Series m (JsonRepr s)) - pure $ objs - where - f (VAEq l) = fromIntegral l diff --git a/src/Data/Schematic/Helpers.hs b/src/Data/Schematic/Helpers.hs index 9620e7b..808fcdb 100644 --- a/src/Data/Schematic/Helpers.hs +++ b/src/Data/Schematic/Helpers.hs @@ -1,6 +1,6 @@ module Data.Schematic.Helpers where -import Data.Schematic.Schema +import Data.Schematic.Constraints import GHC.TypeLits diff --git a/src/Data/Schematic/JsonSchema.hs b/src/Data/Schematic/JsonSchema.hs index 1a4ae82..21d3635 100644 --- a/src/Data/Schematic/JsonSchema.hs +++ b/src/Data/Schematic/JsonSchema.hs @@ -1,7 +1,7 @@ {-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE OverloadedLabels #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE OverloadedLabels #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TemplateHaskell #-} module Data.Schematic.JsonSchema ( toJsonSchema @@ -14,6 +14,7 @@ import Data.Foldable as F import Data.HashMap.Strict as H import Data.List as L import Data.List.NonEmpty as NE +import Data.Schematic.Constraints import Data.Schematic.Schema as S import Data.Set as Set import Data.Singletons @@ -26,40 +27,40 @@ import JSONSchema.Validator.Draft4 as D4 draft4 :: Text draft4 = "http://json-schema.org/draft-04/schema#" -textConstraint :: DemotedTextConstraint -> State D4.Schema () -textConstraint (DTEq n) = modify $ \s -> s +textConstraint :: TextConstraintT -> State D4.Schema () +textConstraint (TEq n) = modify $ \s -> s { _schemaMinLength = pure $ fromIntegral n , _schemaMaxLength = pure $ fromIntegral n } -textConstraint (DTLt n) = modify $ \s -> s +textConstraint (TLt n) = modify $ \s -> s { _schemaMaxLength = pure . fromIntegral $ n + 1 } -textConstraint (DTLe n) = modify $ \s -> s +textConstraint (TLe n) = modify $ \s -> s { _schemaMaxLength = pure . fromIntegral $ n } -textConstraint (DTGt n) = +textConstraint (TGt n) = let n' = if n == 0 then 0 else n - 1 in modify $ \s -> s { _schemaMinLength = pure . fromIntegral $ n' } -textConstraint (DTGe n) = modify $ \s -> s +textConstraint (TGe n) = modify $ \s -> s { _schemaMinLength = pure . fromIntegral $ n } -textConstraint (DTRegex r) = modify $ \s -> s { _schemaPattern = pure r } -textConstraint (DTEnum ss) = +textConstraint (TRegex r) = modify $ \s -> s { _schemaPattern = pure r } +textConstraint (TEnum ss) = let ss' = if F.length ss == 0 then [] else NE.fromList $ J.String <$> ss in modify $ \s -> s { _schemaEnum = pure ss' } -numberConstraint :: DemotedNumberConstraint -> State D4.Schema () -numberConstraint (DNLe n) = modify $ \s -> s +numberConstraint :: NumberConstraintT -> State D4.Schema () +numberConstraint (NLe n) = modify $ \s -> s { _schemaMaximum = pure . fromIntegral $ n } -numberConstraint (DNLt n) = modify $ \s -> s +numberConstraint (NLt n) = modify $ \s -> s { _schemaMaximum = pure . fromIntegral $ n + 1 } -numberConstraint (DNGt n) = modify $ \s -> s +numberConstraint (NGt n) = modify $ \s -> s { _schemaMinimum = pure . fromIntegral $ n } -numberConstraint (DNGe n) = +numberConstraint (NGe n) = let n' = if n == 0 then 0 else n - 1 in modify $ \s -> s { _schemaMinimum = pure . fromIntegral $ n' } -numberConstraint (DNEq n) = modify $ \s -> s +numberConstraint (NEq n) = modify $ \s -> s { _schemaMinimum = pure $ fromIntegral n , _schemaMaximum = pure $ fromIntegral n } -arrayConstraint :: DemotedArrayConstraint -> State D4.Schema () -arrayConstraint (DAEq _) = pure () +arrayConstraint :: ArrayConstraintT -> State D4.Schema () +arrayConstraint (AEq _) = pure () toJsonSchema :: forall proxy schema @@ -71,41 +72,41 @@ toJsonSchema _ = do pure $ js { _schemaVersion = pure draft4 } toJsonSchema' - :: DemotedSchema + :: SchemaT -> Maybe D4.Schema toJsonSchema' = \case - DSchemaText tcs -> + SchemaText tcs -> pure $ execState (traverse_ textConstraint tcs) $ emptySchema { _schemaType = pure $ TypeValidatorString D4.SchemaString } - DSchemaNumber ncs -> + S.SchemaNumber ncs -> pure $ execState (traverse_ numberConstraint ncs) $ emptySchema { _schemaType = pure $ TypeValidatorString D4.SchemaNumber } - DSchemaBoolean -> pure $ emptySchema + S.SchemaBoolean -> pure $ emptySchema { _schemaType = pure $ TypeValidatorString D4.SchemaBoolean } - DSchemaObject objs -> do + S.SchemaObject objs -> do res <- for objs $ \(n,s) -> do s' <- toJsonSchema' s pure (n, s') let nonOpt = \case - (_, DSchemaOptional _) -> False - _ -> True + (_, SchemaOptional _) -> False + _ -> True pure $ emptySchema { _schemaType = pure $ TypeValidatorString D4.SchemaObject , _schemaRequired = pure $ Set.fromList $ fst <$> L.filter nonOpt objs , _schemaProperties = pure $ H.fromList res } - DSchemaArray acs sch -> do + S.SchemaArray acs sch -> do res <- toJsonSchema' sch pure $ execState (traverse_ arrayConstraint acs) $ emptySchema { _schemaType = pure $ TypeValidatorString D4.SchemaArray , _schemaItems = pure $ ItemsObject res } - DSchemaNull -> pure $ emptySchema + S.SchemaNull -> pure $ emptySchema { _schemaType = pure $ TypeValidatorString D4.SchemaNull } - DSchemaOptional sch -> do - snull <- toJsonSchema' DSchemaNull + SchemaOptional sch -> do + snull <- toJsonSchema' S.SchemaNull sres <- toJsonSchema' sch pure $ emptySchema { _schemaOneOf = pure (snull :| [sres]) } - DSchemaUnion sch -> do + SchemaUnion sch -> do schemaUnion <- traverse toJsonSchema' sch >>= \case [] -> Nothing x -> Just x diff --git a/src/Data/Schematic/Migration.hs b/src/Data/Schematic/Migration.hs index b8cc197..1733188 100644 --- a/src/Data/Schematic/Migration.hs +++ b/src/Data/Schematic/Migration.hs @@ -1,10 +1,10 @@ {-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE CPP #-} {-# LANGUAGE TemplateHaskell #-} module Data.Schematic.Migration where import Data.Kind +import Data.Schematic.Compat import Data.Schematic.DSL import Data.Schematic.Lens import Data.Schematic.Path @@ -43,8 +43,8 @@ type family SchemaByKey (fs :: [(Symbol, Schema)]) (s :: Symbol) :: Schema where SchemaByKey ( '(a, s) ': tl) fn = SchemaByKey tl fn type family DeleteKey (acc :: [(Symbol, Schema)]) (fn :: Symbol) (fs :: [(Symbol, Schema)]) :: [(Symbol, Schema)] where - DeleteKey acc fn ('(fn, a) ': tl) = acc ++ tl - DeleteKey acc fn (fna ': tl) = acc ++ (fna ': tl) + DeleteKey acc fn ('(fn, a) ': tl) = acc :++ tl + DeleteKey acc fn (fna ': tl) = acc :++ (fna ': tl) type family UpdateKey (fn :: Symbol) @@ -157,17 +157,12 @@ data MList :: (Type -> Type) -> [Schema] -> Type where infixr 7 :&& -#if MIN_VERSION_base(4,12,0) migrateObject - :: forall m fs fh. (FSubset fs fs (FImage fs fs), Monad m, RMap fh, RMap fs) + :: forall m fs fh + . (FSubset fs fs (FImage fs fs), Monad m, RMapCompat fh, RMapCompat fs) => (Rec (Tagged fs :. FieldRepr) fh -> m (Rec (Tagged fs :. FieldRepr) fs)) - -> Tagged ('SchemaObject fs) (JsonRepr ('SchemaObject fh) -> m (JsonRepr ('SchemaObject fs))) -#else -migrateObject - :: forall m fs fh. (FSubset fs fs (FImage fs fs), Monad m) - => (Rec (Tagged fs :. FieldRepr) fh -> m (Rec (Tagged fs :. FieldRepr) fs)) - -> Tagged ('SchemaObject fs) (JsonRepr ('SchemaObject fh) -> m (JsonRepr ('SchemaObject fs))) -#endif + -> Tagged ('SchemaObject fs) (JsonRepr ('SchemaObject fh) + -> m (JsonRepr ('SchemaObject fs))) migrateObject f = Tagged $ \(ReprObject r) -> do res <- f $ rmap (Compose . Tagged) r pure $ withRepr @('SchemaObject fs) res diff --git a/src/Data/Schematic/Path.hs b/src/Data/Schematic/Path.hs index 566448e..691d077 100644 --- a/src/Data/Schematic/Path.hs +++ b/src/Data/Schematic/Path.hs @@ -1,6 +1,7 @@ module Data.Schematic.Path where import Data.Foldable as F +import Data.Monoid ((<>)) import Data.Singletons.Prelude import Data.Singletons.TypeLits import Data.Text as T @@ -23,11 +24,11 @@ demotePath :: Sing (ps :: [PathSegment]) -> [DemotedPathSegment] demotePath = go [] where go :: [DemotedPathSegment] -> Sing (ps :: [PathSegment]) -> [DemotedPathSegment] - go acc SNil = acc + go acc SNil = acc go acc (SCons p ps) = go (acc ++ [demotePathSeg p]) ps demotePathSeg :: Sing (ps :: PathSegment) -> DemotedPathSegment demotePathSeg (SKey s) = DKey $ T.pack $ withKnownSymbol s $ symbolVal s - demotePathSeg (SIx n) = DIx $ withKnownNat n $ fromIntegral $ natVal n + demotePathSeg (SIx n) = DIx $ withKnownNat n $ fromIntegral $ natVal n demotedPathToText :: [DemotedPathSegment] -> JSONPath demotedPathToText = JSONPath . F.foldl' renderPathSegment "" diff --git a/src/Data/Schematic/Schema.hs b/src/Data/Schematic/Schema.hs index c2bb7c2..dc6d347 100644 --- a/src/Data/Schematic/Schema.hs +++ b/src/Data/Schematic/Schema.hs @@ -1,7 +1,4 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE CPP #-} -{-# LANGUAGE OverloadedLists #-} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE EmptyCase #-} {-# OPTIONS_GHC -fprint-explicit-kinds #-} module Data.Schematic.Schema where @@ -13,8 +10,12 @@ import Data.Aeson.Types as J import Data.HashMap.Strict as H import Data.Kind import Data.Maybe +import Data.Schematic.Compat +import Data.Schematic.Constraints import Data.Schematic.Generator +import Data.Schematic.Generator.Regex import Data.Schematic.Instances () +import Data.Schematic.Verifier.Array import Data.Scientific import Data.Singletons.Prelude.List hiding (All, Union) import Data.Singletons.TH @@ -26,266 +27,25 @@ import Data.Vinyl hiding (Dict) import qualified Data.Vinyl.TypeLevel as V import GHC.Exts import GHC.Generics (Generic) -import GHC.TypeLits - (SomeNat(..), SomeSymbol(..), someNatVal, someSymbolVal) import Prelude as P -import Test.SmallCheck.Series - - -type family CRepr (s :: Schema) :: Type where - CRepr ('SchemaText cs) = TextConstraint - CRepr ('SchemaNumber cs) = NumberConstraint - CRepr ('SchemaObject fs) = (String, Schema) - CRepr ('SchemaArray ar s) = ArrayConstraint - -data TextConstraint - = TEq Nat - | TLt Nat - | TLe Nat - | TGt Nat - | TGe Nat - | TRegex Symbol - | TEnum [Symbol] - deriving (Generic) - -instance SingKind TextConstraint where - type Demote TextConstraint = DemotedTextConstraint - fromSing = \case - STEq n -> withKnownNat n (DTEq . fromIntegral $ natVal n) - STLt n -> withKnownNat n (DTLt . fromIntegral $ natVal n) - STLe n -> withKnownNat n (DTLe . fromIntegral $ natVal n) - STGt n -> withKnownNat n (DTGt . fromIntegral $ natVal n) - STGe n -> withKnownNat n (DTGe . fromIntegral $ natVal n) - STRegex s -> withKnownSymbol s (DTRegex $ T.pack $ symbolVal s) - STEnum s -> let - d :: Sing (s :: [Symbol]) -> [Text] - d SNil = [] - d (SCons ss@SSym fs) = T.pack (symbolVal ss) : d fs - in DTEnum $ d s - toSing = \case - DTEq n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (STEq (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DTLt n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (STLt (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DTLe n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (STLe (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DTGt n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (STGt (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DTGe n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (STGe (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DTRegex s -> case someSymbolVal (T.unpack s) of - SomeSymbol (_ :: Proxy n) -> SomeSing (STRegex (SSym :: Sing n)) - DTEnum ss -> case toSing ss of - SomeSing l -> SomeSing (STEnum l) - -data DemotedTextConstraint - = DTEq Integer - | DTLt Integer - | DTLe Integer - | DTGt Integer - | DTGe Integer - | DTRegex Text - | DTEnum [Text] - deriving (Generic, Eq, Show) - -data instance Sing (tc :: TextConstraint) where - STEq :: Sing n -> Sing ('TEq n) - STLt :: Sing n -> Sing ('TLt n) - STLe :: Sing n -> Sing ('TLe n) - STGt :: Sing n -> Sing ('TGt n) - STGe :: Sing n -> Sing ('TGe n) - STRegex :: Sing s -> Sing ('TRegex s) - STEnum :: Sing ss -> Sing ('TEnum ss) - -instance (KnownNat n) => SingI ('TEq n) where sing = STEq sing -instance (KnownNat n) => SingI ('TGt n) where sing = STGt sing -instance (KnownNat n) => SingI ('TGe n) where sing = STGe sing -instance (KnownNat n) => SingI ('TLt n) where sing = STLt sing -instance (KnownNat n) => SingI ('TLe n) where sing = STLe sing -instance (KnownSymbol s, SingI s) => SingI ('TRegex s) where sing = STRegex sing -instance (SingI ss) => SingI ('TEnum ss) where sing = STEnum sing - -instance Eq (Sing ('TEq n)) where _ == _ = True -instance Eq (Sing ('TLt n)) where _ == _ = True -instance Eq (Sing ('TLe n)) where _ == _ = True -instance Eq (Sing ('TGt n)) where _ == _ = True -instance Eq (Sing ('TGe n)) where _ == _ = True -instance Eq (Sing ('TRegex t)) where _ == _ = True -instance Eq (Sing ('TEnum ss)) where _ == _ = True - -data NumberConstraint - = NLe Nat - | NLt Nat - | NGt Nat - | NGe Nat - | NEq Nat - deriving (Generic) - -data DemotedNumberConstraint - = DNLe Integer - | DNLt Integer - | DNGt Integer - | DNGe Integer - | DNEq Integer - deriving (Generic, Eq, Show) - -data instance Sing (nc :: NumberConstraint) where - SNEq :: Sing n -> Sing ('NEq n) - SNGt :: Sing n -> Sing ('NGt n) - SNGe :: Sing n -> Sing ('NGe n) - SNLt :: Sing n -> Sing ('NLt n) - SNLe :: Sing n -> Sing ('NLe n) - -instance KnownNat n => SingI ('NEq n) where sing = SNEq sing -instance KnownNat n => SingI ('NGt n) where sing = SNGt sing -instance KnownNat n => SingI ('NGe n) where sing = SNGe sing -instance KnownNat n => SingI ('NLt n) where sing = SNLt sing -instance KnownNat n => SingI ('NLe n) where sing = SNLe sing - -instance Eq (Sing ('NEq n)) where _ == _ = True -instance Eq (Sing ('NLt n)) where _ == _ = True -instance Eq (Sing ('NLe n)) where _ == _ = True -instance Eq (Sing ('NGt n)) where _ == _ = True -instance Eq (Sing ('NGe n)) where _ == _ = True - -instance SingKind NumberConstraint where - type Demote NumberConstraint = DemotedNumberConstraint - fromSing = \case - SNEq n -> withKnownNat n (DNEq . fromIntegral $ natVal n) - SNGt n -> withKnownNat n (DNGt . fromIntegral $ natVal n) - SNGe n -> withKnownNat n (DNGe . fromIntegral $ natVal n) - SNLt n -> withKnownNat n (DNLt . fromIntegral $ natVal n) - SNLe n -> withKnownNat n (DNLe . fromIntegral $ natVal n) - toSing = \case - DNEq n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (SNEq (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DNGt n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (SNGt (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DNGe n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (SNGe (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DNLt n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (SNLt (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - DNLe n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (SNLe (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - -data ArrayConstraint - = AEq Nat - deriving (Generic) - -data DemotedArrayConstraint - = DAEq Integer - deriving (Generic, Eq, Show) - -data instance Sing (ac :: ArrayConstraint) where - SAEq :: Sing n -> Sing ('AEq n) - -instance KnownNat n => SingI ('AEq n) where sing = SAEq sing - -instance Eq (Sing ('AEq n)) where _ == _ = True - -instance SingKind ArrayConstraint where - type Demote ArrayConstraint = DemotedArrayConstraint - fromSing = \case - SAEq n -> withKnownNat n (DAEq . fromIntegral $ natVal n) - toSing = \case - DAEq n -> case someNatVal n of - Just (SomeNat (_ :: Proxy n)) -> SomeSing (SAEq (SNat :: Sing n)) - Nothing -> error "Negative singleton nat" - -data Schema - = SchemaText [TextConstraint] - | SchemaBoolean - | SchemaNumber [NumberConstraint] - | SchemaObject [(Symbol, Schema)] - | SchemaArray [ArrayConstraint] Schema - | SchemaNull - | SchemaOptional Schema - | SchemaUnion [Schema] - deriving (Generic) - -data DemotedSchema - = DSchemaText [DemotedTextConstraint] - | DSchemaNumber [DemotedNumberConstraint] - | DSchemaBoolean - | DSchemaObject [(Text, DemotedSchema)] - | DSchemaArray [DemotedArrayConstraint] DemotedSchema - | DSchemaNull - | DSchemaOptional DemotedSchema - | DSchemaUnion [DemotedSchema] - deriving (Generic, Eq, Show) - -data instance Sing (schema :: Schema) where - SSchemaText :: Sing tcs -> Sing ('SchemaText tcs) - SSchemaNumber :: Sing ncs -> Sing ('SchemaNumber ncs) - SSchemaBoolean :: Sing 'SchemaBoolean - SSchemaArray :: Sing acs -> Sing schema -> Sing ('SchemaArray acs schema) - SSchemaObject :: Sing fields -> Sing ('SchemaObject fields) - SSchemaOptional :: Sing s -> Sing ('SchemaOptional s) - SSchemaNull :: Sing 'SchemaNull - SSchemaUnion :: Sing ss -> Sing ('SchemaUnion ss) - -instance SingI sl => SingI ('SchemaText sl) where - sing = SSchemaText sing -instance SingI sl => SingI ('SchemaNumber sl) where - sing = SSchemaNumber sing -instance SingI 'SchemaNull where - sing = SSchemaNull -instance SingI 'SchemaBoolean where - sing = SSchemaBoolean -instance (SingI ac, SingI s) => SingI ('SchemaArray ac s) where - sing = SSchemaArray sing sing -instance SingI stl => SingI ('SchemaObject stl) where - sing = SSchemaObject sing -instance SingI s => SingI ('SchemaOptional s) where - sing = SSchemaOptional sing -instance SingI s => SingI ('SchemaUnion s) where - sing = SSchemaUnion sing - -instance Eq (Sing ('SchemaText cs)) where _ == _ = True -instance Eq (Sing ('SchemaNumber cs)) where _ == _ = True -instance Eq (Sing 'SchemaNull) where _ == _ = True -instance Eq (Sing 'SchemaBoolean) where _ == _ = True -instance Eq (Sing ('SchemaArray as s)) where _ == _ = True -instance Eq (Sing ('SchemaObject cs)) where _ == _ = True -instance Eq (Sing ('SchemaOptional s)) where _ == _ = True -instance Eq (Sing ('SchemaUnion s)) where _ == _ = True - -instance SingKind Schema where - type Demote Schema = DemotedSchema - fromSing = \case - SSchemaText cs -> DSchemaText $ fromSing cs - SSchemaNumber cs -> DSchemaNumber $ fromSing cs - SSchemaBoolean -> DSchemaBoolean - SSchemaArray cs s -> DSchemaArray (fromSing cs) (fromSing s) - SSchemaOptional s -> DSchemaOptional $ fromSing s - SSchemaNull -> DSchemaNull - SSchemaObject cs -> DSchemaObject $ fromSing cs - SSchemaUnion ss -> DSchemaUnion $ fromSing ss - toSing = \case - DSchemaText cs -> case toSing cs of - SomeSing scs -> SomeSing $ SSchemaText scs - DSchemaNumber cs -> case toSing cs of - SomeSing scs -> SomeSing $ SSchemaNumber scs - DSchemaBoolean -> SomeSing $ SSchemaBoolean - DSchemaArray cs sch -> case (toSing cs, toSing sch) of - (SomeSing scs, SomeSing ssch) -> SomeSing $ SSchemaArray scs ssch - DSchemaOptional sch -> case toSing sch of - SomeSing ssch -> SomeSing $ SSchemaOptional ssch - DSchemaNull -> SomeSing SSchemaNull - DSchemaObject cs -> case toSing cs of - SomeSing scs -> SomeSing $ SSchemaObject scs - DSchemaUnion ss -> case toSing ss of - SomeSing sss -> SomeSing $ SSchemaUnion sss +import Test.SmallCheck.Series as S + + +singletons [d| + data Schema' s n + = SchemaText [TextConstraint' s n] + | SchemaBoolean + | SchemaNumber [NumberConstraint' n] + | SchemaObject [(s, Schema' s n)] + | SchemaArray [ArrayConstraint' n] (Schema' s n) + | SchemaNull + | SchemaOptional (Schema' s n) + | SchemaUnion [Schema' s n] + deriving (Show, Generic) + |] + +type SchemaT = Schema' Text (Demote Nat) +type Schema = Schema' Symbol Nat data FieldRepr :: (Symbol, Schema) -> Type where FieldRepr @@ -349,6 +109,19 @@ instance (Monad m, Serial m Scientific, SingI cs) instance Monad m => Serial m (JsonRepr 'SchemaNull) where series = cons0 ReprNull +arraySeries + :: (Monad m, Serial m (JsonRepr s)) + => [ArrayConstraintT] -> S.Series m (V.Vector (JsonRepr s)) +arraySeries cs = maybe (pure V.empty) arraySeries' $ verifyArrayConstraint cs + +arraySeries' + :: forall m s. (Monad m, Serial m (JsonRepr s)) + => Maybe VerifiedArrayConstraint -> S.Series m (V.Vector (JsonRepr s)) +arraySeries' ml = + V.replicateM (maybe minRepeat f ml) (series :: S.Series m (JsonRepr s)) + where + f (VAEq l) = fromIntegral l + instance (Serial m (JsonRepr s), Serial m (V.Vector (JsonRepr s)), SingI cs) => Serial m (JsonRepr ('SchemaArray cs s)) where series = decDepth $ fmap ReprArray @@ -377,16 +150,11 @@ instance Show (JsonRepr 'SchemaNull) where show _ = "ReprNull" instance Show (JsonRepr s) => Show (JsonRepr ('SchemaArray acs s)) where show (ReprArray v) = "ReprArray " P.++ show v -#if MIN_VERSION_base(4,12,0) instance - ( V.RecAll FieldRepr fs Show, RMap fs, ReifyConstraint Show FieldRepr fs - , RecordToList fs ) + ( V.RecAll FieldRepr fs Show, RMapCompat fs + , ReifyConstraintCompat Show FieldRepr fs, RecordToListCompat fs ) => Show (JsonRepr ('SchemaObject fs)) where show (ReprObject fs) = "ReprObject " P.++ show fs -#else -instance V.RecAll FieldRepr fs Show => Show (JsonRepr ('SchemaObject fs)) where - show (ReprObject fs) = "ReprObject " P.++ show fs -#endif instance Show (JsonRepr s) => Show (JsonRepr ('SchemaOptional s)) where show (ReprOptional s) = "ReprOptional " P.++ show s diff --git a/src/Data/Schematic/Schema.hs-boot b/src/Data/Schematic/Schema.hs-boot deleted file mode 100644 index e0444f5..0000000 --- a/src/Data/Schematic/Schema.hs-boot +++ /dev/null @@ -1,87 +0,0 @@ -module Data.Schematic.Schema where - -import Data.Kind -import Data.Maybe -import Data.Schematic.Instances () -import Data.Scientific -import Data.Singletons.TH -import Data.Singletons.TypeLits -import Data.Text as T -import Data.Union -import Data.Vector as V -import Data.Vinyl hiding (Dict) -import Prelude as P - -data TextConstraint - = TEq Nat - | TLt Nat - | TLe Nat - | TGt Nat - | TGe Nat - | TRegex Symbol - | TEnum [Symbol] - -data DemotedTextConstraint - = DTEq Integer - | DTLt Integer - | DTLe Integer - | DTGt Integer - | DTGe Integer - | DTRegex Text - | DTEnum [Text] - -data NumberConstraint - = NLe Nat - | NLt Nat - | NGt Nat - | NGe Nat - | NEq Nat - -data DemotedNumberConstraint - = DNLe Integer - | DNLt Integer - | DNGt Integer - | DNGe Integer - | DNEq Integer - -data ArrayConstraint - = AEq Nat - -data DemotedArrayConstraint - = DAEq Integer - -data Schema - = SchemaText [TextConstraint] - | SchemaBoolean - | SchemaNumber [NumberConstraint] - | SchemaObject [(Symbol, Schema)] - | SchemaArray [ArrayConstraint] Schema - | SchemaNull - | SchemaOptional Schema - | SchemaUnion [Schema] - -data DemotedSchema - = DSchemaText [DemotedTextConstraint] - | DSchemaNumber [DemotedNumberConstraint] - | DSchemaBoolean - | DSchemaObject [(Text, DemotedSchema)] - | DSchemaArray [DemotedArrayConstraint] DemotedSchema - | DSchemaNull - | DSchemaOptional DemotedSchema - | DSchemaUnion [DemotedSchema] - -data FieldRepr :: (Symbol, Schema) -> Type where - FieldRepr - :: (SingI schema, KnownSymbol name) - => JsonRepr schema - -> FieldRepr '(name, schema) - -data JsonRepr :: Schema -> Type where - ReprText :: Text -> JsonRepr ('SchemaText cs) - ReprNumber :: Scientific -> JsonRepr ('SchemaNumber cs) - ReprBoolean :: Bool -> JsonRepr 'SchemaBoolean - ReprNull :: JsonRepr 'SchemaNull - ReprArray :: V.Vector (JsonRepr s) -> JsonRepr ('SchemaArray cs s) - ReprObject :: Rec FieldRepr fs -> JsonRepr ('SchemaObject fs) - ReprOptional :: Maybe (JsonRepr s) -> JsonRepr ('SchemaOptional s) - ReprUnion :: Union JsonRepr (h ': tl) -> JsonRepr ('SchemaUnion (h ': tl)) diff --git a/src/Data/Schematic/Validation.hs b/src/Data/Schematic/Validation.hs index c7605f6..7bb0938 100644 --- a/src/Data/Schematic/Validation.hs +++ b/src/Data/Schematic/Validation.hs @@ -6,7 +6,8 @@ import Data.Aeson import Data.Aeson.Types import Data.Foldable import Data.Functor.Identity -import Data.Monoid +import Data.Monoid ((<>)) +import Data.Schematic.Constraints import Data.Schematic.Path import Data.Schematic.Schema import Data.Scientific @@ -38,7 +39,7 @@ instance (TopLevel a, SingI a, FromJSON (JsonRepr a)) isValid :: ParseResult a -> Bool isValid (Valid _) = True -isValid _ = False +isValid _ = False isDecodingError :: ParseResult a -> Bool isDecodingError (DecodingError _) = True diff --git a/src/Data/Schematic/Verifier/Array.hs b/src/Data/Schematic/Verifier/Array.hs index 7280f55..71a3b32 100644 --- a/src/Data/Schematic/Verifier/Array.hs +++ b/src/Data/Schematic/Verifier/Array.hs @@ -1,14 +1,14 @@ module Data.Schematic.Verifier.Array where -import {-# SOURCE #-} Data.Schematic.Schema +import Data.Schematic.Compat +import Data.Schematic.Constraints import Data.Schematic.Verifier.Common + data VerifiedArrayConstraint = - VAEq Integer + VAEq DeNat deriving (Show) -verifyArrayConstraint :: - [DemotedArrayConstraint] -> Maybe (Maybe VerifiedArrayConstraint) -verifyArrayConstraint cs = do - x <- verifyDNEq [x | DAEq x <- cs] - pure $ VAEq <$> x +verifyArrayConstraint + :: [ArrayConstraintT] -> Maybe (Maybe VerifiedArrayConstraint) +verifyArrayConstraint cs = fmap VAEq <$> verifyNEq [x | AEq x <- cs] diff --git a/src/Data/Schematic/Verifier/Common.hs b/src/Data/Schematic/Verifier/Common.hs index d334878..9406b76 100644 --- a/src/Data/Schematic/Verifier/Common.hs +++ b/src/Data/Schematic/Verifier/Common.hs @@ -1,41 +1,43 @@ module Data.Schematic.Verifier.Common where import Data.List (nub) +import Data.Schematic.Compat -simplifyNumberConstraint :: ([Integer] -> Integer) -> [Integer] -> Maybe Integer + +simplifyNumberConstraint :: ([DeNat] -> DeNat) -> [DeNat] -> Maybe DeNat simplifyNumberConstraint f = \case [] -> Nothing x -> Just $ f x -simplifyDNLs :: [Integer] -> Maybe Integer -simplifyDNLs = simplifyNumberConstraint minimum +simplifyNLs :: [DeNat] -> Maybe DeNat +simplifyNLs = simplifyNumberConstraint minimum -simplifyDNGs :: [Integer] -> Maybe Integer -simplifyDNGs = simplifyNumberConstraint maximum +simplifyNGs :: [DeNat] -> Maybe DeNat +simplifyNGs = simplifyNumberConstraint maximum -verifyDNEq :: [Integer] -> Maybe (Maybe Integer) -verifyDNEq x = +verifyNEq :: [DeNat] -> Maybe (Maybe DeNat) +verifyNEq x = case nub x of [] -> Just Nothing [y] -> Just $ Just y (_:_:_) -> Nothing -verify3 :: Maybe Integer -> Maybe Integer -> Maybe Integer -> Maybe () +verify3 :: Maybe DeNat -> Maybe DeNat -> Maybe DeNat -> Maybe () verify3 (Just x) (Just y) (Just z) = if x < y && y < z then Just () else Nothing verify3 _ _ _ = Just () -verify2 :: Maybe Integer -> Maybe Integer -> Maybe () +verify2 :: Maybe DeNat -> Maybe DeNat -> Maybe () verify2 (Just x) (Just y) = if x < y then Just () else Nothing verify2 _ _ = Just () -verifyEquations :: Maybe Integer -> Maybe Integer -> Maybe Integer -> Maybe () +verifyEquations :: Maybe DeNat -> Maybe DeNat -> Maybe DeNat -> Maybe () verifyEquations mgt meq mlt = do verify3 mgt meq mlt verify2 mgt meq diff --git a/src/Data/Schematic/Verifier/Number.hs b/src/Data/Schematic/Verifier/Number.hs index a8d239b..5e41cc9 100644 --- a/src/Data/Schematic/Verifier/Number.hs +++ b/src/Data/Schematic/Verifier/Number.hs @@ -1,29 +1,31 @@ module Data.Schematic.Verifier.Number where -import {-# SOURCE #-} Data.Schematic.Schema +import Data.Schematic.Compat +import Data.Schematic.Constraints import Data.Schematic.Verifier.Common -toStrictNumber :: [DemotedNumberConstraint] -> [DemotedNumberConstraint] + +toStrictNumber :: [NumberConstraintT] -> [NumberConstraintT] toStrictNumber = map f where - f (DNLe x) = DNLt (x + 1) - f (DNGe x) = DNGt (x - 1) - f x = x + f (NLe x) = NLt (x + 1) + f (NGe x) = NGt (x - 1) + f x = x data VerifiedNumberConstraint - = VNEq Integer - | VNBounds (Maybe Integer) (Maybe Integer) + = VNEq DeNat + | VNBounds (Maybe DeNat) (Maybe DeNat) deriving (Show) verifyNumberConstraints - :: [DemotedNumberConstraint] + :: [NumberConstraintT] -> Maybe VerifiedNumberConstraint verifyNumberConstraints cs' = do let cs = toStrictNumber cs' - mlt = simplifyDNLs [x | DNLt x <- cs] - mgt = simplifyDNGs [x | DNGt x <- cs] - meq <- verifyDNEq [x | DNEq x <- cs] + mlt = simplifyNLs [x | NLt x <- cs] + mgt = simplifyNGs [x | NGt x <- cs] + meq <- verifyNEq [x | NEq x <- cs] verifyEquations mgt meq mlt Just $ case meq of diff --git a/src/Data/Schematic/Verifier/Text.hs b/src/Data/Schematic/Verifier/Text.hs index 485db87..0c0b5de 100644 --- a/src/Data/Schematic/Verifier/Text.hs +++ b/src/Data/Schematic/Verifier/Text.hs @@ -2,37 +2,39 @@ module Data.Schematic.Verifier.Text where import Control.Monad import Data.Maybe -import {-# SOURCE #-} Data.Schematic.Schema +import Data.Schematic.Compat +import Data.Schematic.Constraints import Data.Schematic.Verifier.Common import Data.Text (Text, unpack) import Text.Regex.TDFA.Pattern import Text.Regex.TDFA.ReadRegex (parseRegex) -toStrictTextLength :: [DemotedTextConstraint] -> [DemotedTextConstraint] + +toStrictTextLength :: [TextConstraintT] -> [TextConstraintT] toStrictTextLength = map f where - f (DTLe x) = DTLt (x + 1) - f (DTGe x) = DTGt (x - 1) - f x = x + f (TLe x) = TLt (x + 1) + f (TGe x) = TGt (x - 1) + f x = x data VerifiedTextConstraint - = VTEq Integer - | VTBounds (Maybe Integer) (Maybe Integer) - | VTRegex Text Integer (Maybe Integer) + = VTEq DeNat + | VTBounds (Maybe DeNat) (Maybe DeNat) + | VTRegex Text DeNat (Maybe DeNat) | VTEnum [Text] deriving (Show) verifyTextLengthConstraints - :: [DemotedTextConstraint] + :: [TextConstraintT] -> Maybe (Maybe VerifiedTextConstraint) verifyTextLengthConstraints cs' = do let cs = toStrictTextLength cs' - mlt = simplifyDNLs [x | DTLt x <- cs] - mgt = simplifyDNGs [x | DTGt x <- cs] - meq <- verifyDNEq [x | DTEq x <- cs] + mlt = simplifyNLs [x | TLt x <- cs] + mgt = simplifyNGs [x | TGt x <- cs] + meq <- verifyNEq [x | TEq x <- cs] verifyEquations mgt meq mlt - case all isNothing ([mgt, meq, mlt] :: [Maybe Integer]) of + case all isNothing ([mgt, meq, mlt] :: [Maybe DeNat]) of True -> Just Nothing _ -> Just $ @@ -86,10 +88,10 @@ maxRegexLength p = _ -> Just 0 verifyTextRegexConstraint - :: [DemotedTextConstraint] + :: [TextConstraintT] -> Maybe (Maybe VerifiedTextConstraint) verifyTextRegexConstraint cs = do - let regexps = [x | DTRegex x <- cs] + let regexps = [x | TRegex x <- cs] case regexps of [] -> Just Nothing [x] -> do @@ -98,23 +100,23 @@ verifyTextRegexConstraint cs = do _ -> Nothing verifyTextEnumConstraint - :: [DemotedTextConstraint] + :: [TextConstraintT] -> Maybe (Maybe VerifiedTextConstraint) verifyTextEnumConstraint cs = do - let enums = concat [x | DTEnum x <- cs] + let enums = concat [x | TEnum x <- cs] case enums of [] -> Just Nothing x -> Just $ Just $ VTEnum x verifyTextConstraints - :: [DemotedTextConstraint] + :: [TextConstraintT] -> Maybe [VerifiedTextConstraint] verifyTextConstraints cs = do regexp <- verifyTextRegexConstraint cs void $ case regexp of Just (VTRegex _ l mh) -> - verifyTextLengthConstraints (DTGe l : cs ++ maybeToList (DTLe <$> mh)) + verifyTextLengthConstraints (TGe l : cs ++ maybeToList (TLe <$> mh)) _ -> pure Nothing lengths <- verifyTextLengthConstraints cs enums <- verifyTextEnumConstraint cs diff --git a/stack.yaml b/stack.yaml index 8b81f4c..cdda15d 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,6 @@ -resolver: lts-12.0 +resolver: lts-13.7 +# resolver: lts-12.0 +# resolver: lts-10.0 extra-deps: - hjsonpointer-1.4.0@rev:0 - hjsonschema-1.9.0@rev:0 diff --git a/test/HelpersSpec.hs b/test/HelpersSpec.hs index 65d2255..dff1243 100644 --- a/test/HelpersSpec.hs +++ b/test/HelpersSpec.hs @@ -1,17 +1,16 @@ {-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-} - -{-# LANGUAGE LambdaCase #-} - -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeApplications #-} module HelpersSpec (spec, main) where import Control.Lens import Data.ByteString.Lazy.Lens import Data.Foldable -import Data.Monoid +import Data.Monoid ((<>)) import Data.Schematic import Data.Text as T import Data.Text.Lens diff --git a/test/JsonSchemaSpec.hs b/test/JsonSchemaSpec.hs index 312c919..762ac8b 100644 --- a/test/JsonSchemaSpec.hs +++ b/test/JsonSchemaSpec.hs @@ -1,9 +1,10 @@ -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE OverloadedLists #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeApplications #-} module JsonSchemaSpec (spec, main) where diff --git a/test/LensSpec.hs b/test/LensSpec.hs index b28d1c0..a15ef99 100644 --- a/test/LensSpec.hs +++ b/test/LensSpec.hs @@ -1,12 +1,12 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE OverloadedLists #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeApplications #-} module LensSpec (spec, main) where import Control.Lens -import Data.Proxy import Data.Schematic import Data.Vinyl import Test.Hspec @@ -301,7 +301,6 @@ spec :: Spec spec = do let newFooVal = FieldRepr $ ReprArray [ReprNumber 15] - fooProxy = Proxy @"foo" it "gets the field from an object" $ do fget @"foo" objectData `shouldBe` arrayField it "sets the object field" $ do diff --git a/test/SchemaSpec.hs b/test/SchemaSpec.hs index 3ce30ad..89ce8f7 100644 --- a/test/SchemaSpec.hs +++ b/test/SchemaSpec.hs @@ -1,33 +1,28 @@ {-# OPTIONS_GHC -fprint-potential-instances #-} - -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE OverloadedLists #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} +{-# OPTIONS_GHC -fno-warn-unused-top-binds #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE OverloadedLists #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeApplications #-} module SchemaSpec (spec, main) where import Control.Lens import Data.Aeson import Data.ByteString.Lazy -import Data.Functor.Identity +import Data.Monoid ((<>)) import Data.Proxy import Data.Schematic -import Data.Schematic.Generator -import Data.Singletons -import Data.Tagged import Data.Vinyl import Test.Hspec import Test.Hspec.SmallCheck import Test.SmallCheck as SC -import Test.SmallCheck.Drivers as SC import Test.SmallCheck.Series as SC -import Debug.Trace type SchemaExample = 'SchemaObject '[ '("foo", 'SchemaArray '[ 'AEq 1] ('SchemaNumber '[ 'NGt 10])) @@ -37,6 +32,12 @@ type SchemaExample2 = 'SchemaObject '[ '("foo", 'SchemaArray '[ 'AEq 2] ('SchemaText '[ 'TGt 10])) , '("bar", 'SchemaOptional ('SchemaText '[ 'TRegex "[0-9]+"]))] +type SchemaExample3 = 'SchemaUnion '[SchemaExample] + +type SchemaExample4 = 'SchemaObject + '[ '("baz3", SchemaExample3) + , '("baz1", SchemaExample)] + jsonExample :: JsonRepr SchemaExample jsonExample = withRepr @SchemaExample $ field @"bar" (Just "bar") @@ -45,7 +46,7 @@ jsonExample = withRepr @SchemaExample type AddQuuz = 'Migration "add_field_quuz" - '[ 'Diff '[] ('AddKey "quuz" (SchemaNumber '[])) ] + '[ 'Diff '[] ('AddKey "quuz" ('SchemaNumber '[])) ] type DeleteQuuz = 'Migration "remove_field_quuz" @@ -86,6 +87,12 @@ schemaJsonSeries = series schemaJsonSeries2 :: Monad m => SC.Series m (JsonRepr SchemaExample2) schemaJsonSeries2 = series +schemaJson3 :: ByteString +schemaJson3 = schemaJson + +schemaJson4 :: ByteString +schemaJson4 = "{\"baz1\": "<>schemaJson<>", \"baz3\": "<>schemaJson3<>"}" + spec :: Spec spec = do -- it "show/read JsonRepr properly" $