From 3cd0fd425eeed6e037831473387e36dbcdca546b Mon Sep 17 00:00:00 2001 From: Arjun Kathuria Date: Fri, 5 Jul 2024 14:45:11 +0530 Subject: [PATCH 1/7] [GHC Upgrade]: Fix Aeson V2.x breaking changes This commit fixes the breaking changes that come with Aeson V2.x update while upgrading to GHC 9.2.8 and related package set. Aeson Changed the internal representation of Object from HashMap -> newer KeyMap. The choice here was to:- 1. Change the underlying internal representation of `ObjectF` from HashMap to KeyMap 2. Do conversions between HashMap and KeyMap at endpoints or nodal code that requires it. In order to keep the changes and downstream breakage minimal, approach 2 of conversion where required was chosen. --- src/Data/Medea.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Data/Medea.hs b/src/Data/Medea.hs index a19200a..6af77c8 100644 --- a/src/Data/Medea.hs +++ b/src/Data/Medea.hs @@ -77,6 +77,7 @@ import Control.Monad.RWS.Strict (RWST (..), evalRWST) import Control.Monad.Reader (MonadReader, asks) import Control.Monad.State.Strict (MonadState (..), gets) import Data.Aeson (Array, Object, Value (..), decodeStrict) +import qualified Data.Aeson.KeyMap as AKM import qualified Data.ByteString as BS import Data.ByteString (ByteString) import Data.Can (Can (..)) @@ -163,7 +164,7 @@ toValue (ValidatedJSON (_ :< f)) = case f of NumberF n -> Number n StringF s -> String s ArrayF v -> Array . fmap (toValue . coerce) $ v - ObjectF hm -> Object . fmap (toValue . coerce) $ hm + ObjectF hm -> Object . fmap (toValue . coerce) $ AKM.fromHashMapText hm -- | What schema did this validate against? validAgainst :: ValidatedJSON -> SchemaInformation @@ -332,7 +333,7 @@ checkPrim v = do Object obj -> case par of -- Fast path (no object spec) Nothing -> - put (anySet, Nothing) >> (ObjectSchema :<) . ObjectF <$> traverse checkTypes obj + put (anySet, Nothing) >> (ObjectSchema :<) . ObjectF <$> traverse checkTypes (AKM.toHashMapText obj) Just parIdent -> checkObject obj parIdent -- check if the array satisfies the corresponding specification. @@ -361,7 +362,7 @@ checkArray arr parIdent = do -- check if object properties satisfy the corresponding specification. checkObject :: Object -> Identifier -> ValidationM (Cofree ValidJSONF SchemaInformation) checkObject obj parIdent = do - valsAndTypes <- pairPropertySchemaAndVal obj parIdent + valsAndTypes <- pairPropertySchemaAndVal (AKM.toHashMapText obj) parIdent checkedObj <- traverse go valsAndTypes pure (ObjectSchema :< ObjectF checkedObj) where From 55d34214901bc317afd2c2190d24604a81a38b81 Mon Sep 17 00:00:00 2001 From: Arjun Kathuria Date: Fri, 5 Jul 2024 14:58:41 +0530 Subject: [PATCH 2/7] [GHC Upgrade]: Add missing Eq instance for `ValidJSONF` type This commit fixes the compilation error where it reported that `ValidJSONF` type was missing an `Eq` type-class instance, owing to the `Hashable` instance of `ValidJSONF` Adds the required `Eq` instance to the type's already existing type-class derivation list. --- src/Data/Medea/ValidJSON.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Medea/ValidJSON.hs b/src/Data/Medea/ValidJSON.hs index 71b4036..06f6c17 100644 --- a/src/Data/Medea/ValidJSON.hs +++ b/src/Data/Medea/ValidJSON.hs @@ -24,7 +24,7 @@ data ValidJSONF a | StringF {-# UNPACK #-} !Text | ArrayF {-# UNPACK #-} !(Vector a) | ObjectF !(HashMap Text a) - deriving stock (Functor, Typeable, Data) + deriving stock (Functor, Typeable, Data, Eq) instance Foldable ValidJSONF where {-# INLINE foldMap #-} From 01f20fd53cee696b8649e4f1e0942252eaf7bd89 Mon Sep 17 00:00:00 2001 From: Arjun Kathuria Date: Mon, 8 Jul 2024 14:57:31 +0530 Subject: [PATCH 3/7] [GHC Upgrade]: Fix broken test-suite This commit fixes broken project test-suite after the upgrade. There were the usual Aeson V2.x breakages. Main changes: * Convert between `HashMap` <-> `KeyMap` type as required * Convert between keys from `Text` <-> `Key` type for `KeyMap` keys * Add relevant import statements to import these data types and functions --- test/Data/Aeson/Arbitrary.hs | 3 ++- test/validator-quickcheck/Main.hs | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/Data/Aeson/Arbitrary.hs b/test/Data/Aeson/Arbitrary.hs index 29eb0ae..b851e86 100644 --- a/test/Data/Aeson/Arbitrary.hs +++ b/test/Data/Aeson/Arbitrary.hs @@ -19,6 +19,7 @@ import Control.Monad (filterM, replicateM) import Control.Monad.Reader (ReaderT, asks, local, runReaderT) import Control.Monad.Trans (lift) import Data.Aeson (Array, Object, Value (..)) +import qualified Data.Aeson.KeyMap as AKM import qualified Data.HashMap.Strict as HM import Data.Text (Text) import qualified Data.Vector as V @@ -93,7 +94,7 @@ makeRandomObject (ObjGenOpts props optionalProps minAdditional maxAdditional) = someOptionalProps <- filterM (\_ -> lift arbitrary) optionalProps let keys = genKeys ++ props ++ someOptionalProps keyVals <- mapM (\x -> (x,) <$> local dec makeRandomValue) keys - pure . HM.fromList $ keyVals + pure . AKM.fromHashMapText . HM.fromList $ keyVals dec :: Word -> Word dec = subtract 1 diff --git a/test/validator-quickcheck/Main.hs b/test/validator-quickcheck/Main.hs index 3367a3d..c4cf53b 100644 --- a/test/validator-quickcheck/Main.hs +++ b/test/validator-quickcheck/Main.hs @@ -15,6 +15,8 @@ import Data.Aeson.Arbitrary isObject, isString, ) +import qualified Data.Aeson.Key as AesonKey +import qualified Data.Aeson.KeyMap as AKM import Data.ByteString.Lazy (toStrict) import Data.Either (isLeft, isRight) import Data.HashMap.Strict (filterWithKey, lookup) @@ -293,16 +295,16 @@ validationFail gen p scm = property $ forAll gen prop -- Returns true iff the value is an object with the given property and the -- property-value satisfies the predicate. hasProperty :: Text -> (Value -> Bool) -> Object -> Bool -hasProperty propName p obj = maybe False p $ lookup propName obj +hasProperty propName p obj = maybe False p $ AKM.lookup (AesonKey.fromText propName) obj -- Like hasProperty but is also true when the given property is absent. hasOptionalProperty :: Text -> (Value -> Bool) -> Object -> Bool -hasOptionalProperty propName p obj = maybe True p $ lookup propName obj +hasOptionalProperty propName p obj = maybe True p $ AKM.lookup (AesonKey.fromText propName) obj makeMapPred :: ObjGenOpts -> (Value -> Bool) -> Object -> Bool -makeMapPred (ObjGenOpts props optProps _ _) p = all p . filterWithKey (\k _ -> k `notElem` specifiedProps) +makeMapPred (ObjGenOpts props optProps _ _) p = all p . AKM.filterWithKey (\k _ -> k `notElem` specifiedProps) where - specifiedProps = props ++ optProps + specifiedProps = fmap (AesonKey.fromText) $ props ++ optProps testStringVals :: FilePath -> [String] -> Spec testStringVals fp validStrings = do From 1ecc16d25c4e2cd56f58aa0c09086ca0bee15500 Mon Sep 17 00:00:00 2001 From: Arjun Kathuria Date: Mon, 8 Jul 2024 15:38:51 +0530 Subject: [PATCH 4/7] [GHC Upgrade]: Update stack.yaml file with GHC-9.2.8 lts-20.26 resolver This commit updates the stackage resolver to lts-20.26, the lastest one with ghc 9.2.8 in stack.yaml file. It upgrades to that from the previous 15.15, which is very old. (GHC 8.8.x) Main changes: * Updates resolver to lts-20.26, GHC 9.2.8 set. * Removes older extra dependency pins from extra-deps section * Adds additional packages to extra-deps section required to build with GHC 9.2.8 now (was just one of those) --- stack.yaml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/stack.yaml b/stack.yaml index 4752810..8b14d6f 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,12 +1,6 @@ --- -resolver: lts-15.15 +resolver: lts-20.26 packages: - . extra-deps: - - megaparsec-8.0.0@sha256:362f85e243ecbcb550e1de6e5c74ba5a50c09edaa1208c99bc5b9fd242227fc6,3808 - - microlens-ghc-0.4.12@sha256:77337e3222c900011df2bd3dd55d90367ee90c6c8904f4f2826d6dd874945f35,2505 - - microlens-0.4.11.2@sha256:765ec5cdd12a459e65161f0e3cdbce84652bf634d62af3911ba24e4bf8d4d944,4455 - - algebraic-graphs-0.5@sha256:6eeec5ed1687ff7aa916e7bf9f02f51aaabde6f314dc0b7b1a84156974d7da73,8071 - - nonempty-containers-0.3.3.0@sha256:f306bdbb271fb43057e0205293915bbfafc92f9960d89c0ea457625aad752eca,2717 - - nonempty-vector-0.2.0.1@sha256:332f8d48b5de02c1ab4e52c99973d4ca42dcbce21a073ffd1b5b2da1221e113f,1753 - - smash-0.1.1.0@sha256:593381bad038ff93898a8a1422c6e81fc4a2a6fb23b64afa2f758f56607b83dc,1583 + - smash-0.1.3@sha256:e812275cad1fac9d6f8a479f08c1622ae5e694506883c75e26f4c93895bebca8,1351 From bf9e9030aad7867fb5ef89bcd6c45f3c427051cd Mon Sep 17 00:00:00 2001 From: Arjun Kathuria Date: Mon, 8 Jul 2024 16:01:14 +0530 Subject: [PATCH 5/7] [GHC Upgrade]: Update medea.cabal file, add new cabal.project file This commit updates the cabal file of the project to go with the GHC 9.2.8 upgrade. It also adds a new "cabal.project" file for better Nix support. Main changes: * Updates package version to "1.3.0" from previous "1.2.0" * Removes version bounds from dependency packages in cabal file. These would come from the stack package set or the Nix package set, which used with Nix. * Adds GHC 9.2.8 to 'tested-with' section * Adds a new cabal.project file to the project, for better Nix support. --- cabal.project | 2 ++ medea.cabal | 54 +++++++++++++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 27 deletions(-) create mode 100644 cabal.project diff --git a/cabal.project b/cabal.project new file mode 100644 index 0000000..b764c34 --- /dev/null +++ b/cabal.project @@ -0,0 +1,2 @@ +packages: . + diff --git a/medea.cabal b/medea.cabal index c22233a..dced080 100644 --- a/medea.cabal +++ b/medea.cabal @@ -1,6 +1,6 @@ cabal-version: 2.2 name: medea -version: 1.2.0 +version: 1.3.0 synopsis: A schema language for JSON. description: A reference implementation of a schema language, together with a conformance @@ -18,7 +18,7 @@ maintainer: koz.ross@retro-freedom.nz copyright: Juspay Technologies Pvt Ltd (C) 2020 category: Data build-type: Simple -tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.1 +tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.1 || ==9.2.8 extra-source-files: .hspec CHANGELOG.md @@ -46,9 +46,9 @@ common test-common import: lang-common other-modules: TestM build-depends: - , directory ^>=1.3.3.0 - , filepath ^>=1.4.2.1 - , hspec >=2.7.1 && <2.9.0 + , directory + , filepath + , hspec , medea , mtl @@ -75,24 +75,24 @@ library Data.Medea.ValidJSON build-depends: - , aeson >=1.4.6.0 && <2.0.0.0 - , algebraic-graphs ^>=0.5 - , bytestring ^>=0.10.8.2 - , containers ^>=0.6.0.1 - , deepseq ^>=1.4.4.0 - , free ^>=5.1.3 - , hashable >=1.2.7.0 && <1.4.0.0 - , megaparsec >=8.0.0 && <10.0.0 - , microlens-ghc ^>=0.4.12 - , mtl ^>=2.2.2 - , nonempty-containers ^>=0.3.3.0 - , parser-combinators >=1.1.0 && <2.0.0 - , scientific ^>=0.3.6.2 - , smash ^>=0.1.1.0 - , text ^>=1.2.3.1 - , unordered-containers ^>=0.2.10.0 - , vector ^>=0.12.0.3 - , vector-instances ^>=3.4 + , aeson + , algebraic-graphs + , bytestring + , containers + , deepseq + , free + , hashable + , megaparsec + , microlens-ghc + , mtl + , nonempty-containers + , parser-combinators + , scientific + , smash + , text + , unordered-containers + , vector + , vector-instances hs-source-dirs: src @@ -116,11 +116,11 @@ test-suite quickcheck-validator build-depends: , aeson , bytestring - , hspec-core >=2.7.1 && <2.9.0 - , QuickCheck >=2.13.2 && <2.15.0 - , quickcheck-instances ^>=0.3.22 + , hspec-core + , QuickCheck + , quickcheck-instances , text - , unordered-containers ^>=0.2.10.0 + , unordered-containers , vector hs-source-dirs: test/validator-quickcheck From 0037ddd08acec226146c6e6a37e68bba8dfc495c Mon Sep 17 00:00:00 2001 From: Arjun Kathuria Date: Mon, 8 Jul 2024 16:15:40 +0530 Subject: [PATCH 6/7] [GHC Upgrade]: Update CHANGELOG.md This commit updates CHANGELOG.md file with the new version That supports building with GHC 9.2.8 Adds the list of main changes done to get working GHC 9.2.8 support to project in the CHANGELOG.md file, filed under new version "1.3.0". --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e959e80..a8ff068 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Dev +# 1.3.0 + +- Adds GHC 9.2.8 support +- Fix build errors with GHC 9.2.8 +- Remove version bounds on dependency packages in Cabal file +- Adds new "cabal.project" file to project +- Handle Aeson V2.x `KeyMap` <-> `HashMap` data-type changes +- Handle Aeson V2.x `Key` <-> `Text` key-type changes +- Fix broken test-suite after project GHC upgrade +- Test with GHC 9.2.8 +- Update `stack.yaml` to use LTS 20.26 (ghc 9.2.8 package-set) + # 1.2.0 - Widen QuickCheck bounds. From 49b1079c8ba2172c5b0a56ac0fafe791637b02fa Mon Sep 17 00:00:00 2001 From: Arjun Kathuria Date: Mon, 8 Jul 2024 16:21:08 +0530 Subject: [PATCH 7/7] [GHC Upgrade]: Cleanup and housekeeping This commit cleans up the left-over vestiges of now un-needed code. This commit removes a now redundant import statement from test-suite. --- test/validator-quickcheck/Main.hs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/validator-quickcheck/Main.hs b/test/validator-quickcheck/Main.hs index c4cf53b..9564705 100644 --- a/test/validator-quickcheck/Main.hs +++ b/test/validator-quickcheck/Main.hs @@ -19,7 +19,6 @@ import qualified Data.Aeson.Key as AesonKey import qualified Data.Aeson.KeyMap as AKM import Data.ByteString.Lazy (toStrict) import Data.Either (isLeft, isRight) -import Data.HashMap.Strict (filterWithKey, lookup) import Data.Medea (Schema, loadSchemaFromFile, validate) import Data.Text (Text) import qualified Data.Vector as V