aeson-injector 1.0.3.0 → 1.0.4.0
raw patch · 4 files changed
+126/−3 lines, 4 filesdep +scientificdep +vectordep ~aesonPVP ok
version bump matches the API change (PVP)
Dependencies added: scientific, vector
Dependency ranges changed: aeson
API changes (from Hackage documentation)
+ Data.Aeson.Unit: Unit :: Unit
+ Data.Aeson.Unit: data Unit
+ Data.Aeson.Unit: instance Data.Aeson.Types.Class.FromJSON Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance Data.Aeson.Types.Class.ToJSON Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance Data.Swagger.Internal.Schema.ToSchema Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance GHC.Classes.Eq Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance GHC.Enum.Bounded Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance GHC.Enum.Enum Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance GHC.Generics.Generic Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance GHC.Read.Read Data.Aeson.Unit.Unit
+ Data.Aeson.Unit: instance GHC.Show.Show Data.Aeson.Unit.Unit
Files
- CHANGELOG.md +14/−0
- aeson-injector.cabal +7/−3
- src/Data/Aeson/Unit.hs +52/−0
- test/Main.hs +53/−0
+ CHANGELOG.md view
@@ -0,0 +1,14 @@+1.0.4.0+=======++- Add `Data.Aeson.Unit` module.++1.0.3.0+=======++- Add [servant-docs](https://hackage.haskell.org/package/servant-docs) instances.++1.0.2.0+=======++- Add `OnlyField` data type.
aeson-injector.cabal view
@@ -1,5 +1,5 @@ name: aeson-injector-version: 1.0.3.0+version: 1.0.4.0 synopsis: Injecting fields into aeson values description: See README.md license: MIT@@ -16,7 +16,8 @@ , GHC == 8.0.2 extra-source-files: README.md -+ CHANGELOG.md + source-repository head type: git location: https://github.com/NCrashed/aeson-injector@@ -25,11 +26,12 @@ default-language: Haskell2010 hs-source-dirs: src exposed-modules:+ Data.Aeson.Unit Data.Aeson.WithField build-depends: base >= 4.7 && < 4.10- , aeson >= 0.11 && < 0.13+ , aeson >= 0.11 && < 1 , bifunctors >= 5.2 && < 6 , deepseq >= 1.4 && < 2 , lens >= 4.13 && < 5@@ -51,8 +53,10 @@ , lens , QuickCheck >= 2.8.2 , quickcheck-text+ , scientific , swagger2 , tasty >= 0.11 , tasty-hunit >= 0.9 , tasty-quickcheck >= 0.8 , text+ , vector
+ src/Data/Aeson/Unit.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE DeriveGeneric #-}+{-|+Module : Data.Aeson.Unit+Description : Provides unit type that serialises into empty JSON object+Copyright : (c) Anton Gushcha, 2016+License : MIT+Maintainer : ncrashed@gmail.com+Stability : experimental+Portability : Portable++Common problem in REST interfaces when you need to return nothing as result, +usage of `()` will produce `[]` JSON. That causes problems in some JSON parsers+in other languages. ++So, `Unit` serialises into empty JSON object:++>>> encode Unit+"{}"++-}+module Data.Aeson.Unit(+ Unit(..)+ ) where ++import Control.Lens+import Data.Aeson +import Data.Swagger+import GHC.Generics ++-- | Data type that serialise into empty object in aeson+--+-- >>> encode Unit+-- "{}"+--+-- >>> encode $ toSchema (Proxy :: Proxy Unit)+-- "{\"type\":\"object\"}"+--+-- Also the 'FromJSON' instance is just `pure Unit`, so it never fails.+data Unit = Unit+ deriving (Generic, Eq, Show, Read, Enum, Bounded)++instance ToJSON Unit where + toJSON _ = object []++-- | Always a success parse +instance FromJSON Unit where + parseJSON _ = pure Unit++instance ToSchema Unit where + declareNamedSchema _ = do + return $ NamedSchema Nothing $ mempty+ & type_ .~ SwaggerObject
test/Main.hs view
@@ -8,8 +8,10 @@ import Control.Lens hiding ((.=)) import Control.Monad import Data.Aeson as A +import Data.Aeson.Unit import Data.Aeson.WithField import Data.Proxy+import Data.Scientific (scientific) import Data.Swagger import Data.Swagger.Internal.Schema import Data.Text@@ -18,6 +20,8 @@ import Test.Tasty.HUnit import Test.Tasty.QuickCheck as QC +import qualified Data.Vector as V + instance (Arbitrary a, Arbitrary b) => Arbitrary (WithField s a b) where arbitrary = WithField <$> arbitrary <*> arbitrary @@ -27,6 +31,17 @@ instance Arbitrary a => Arbitrary (OnlyField s a) where arbitrary = OnlyField <$> arbitrary +instance Arbitrary Value where + arbitrary = oneof [obj, arr]+ where + json = oneof [obj, arr, str, num, bl, nullg]+ obj = object <$> listOf ((.=) <$> arbitrary <*> json) + arr = Array . V.fromList <$> listOf json+ str = String <$> arbitrary+ num = fmap Number $ scientific <$> arbitrary <*> arbitrary+ bl = Bool <$> arbitrary+ nullg = pure Null + main :: IO () main = defaultMain tests @@ -38,6 +53,7 @@ withFieldProps , withFieldsProps , onlyFieldProps+ , unitDataProps ] unitTests :: TestTree @@ -45,6 +61,7 @@ withFieldTests , withFieldsTests , onlyFieldTests+ , unitDataTests ] data TestObj = TestObj !Text @@ -314,6 +331,32 @@ expected @=? (actual ^. properties) ] +unitDataTests :: TestTree+unitDataTests = testGroup "Unit tests" [+ testsToJSON + , testsFromJSON + , testsToSchema+ ]+ where + testsToJSON = testGroup "toJSON" [+ testCase "Normal mode" $ do + let expected = object [ ]+ let actual = toJSON Unit+ expected @=? actual+ ]+ testsFromJSON = testGroup "FromJSON" [+ testCase "Normal mode" $ do + let expected = Unit+ let (A.Success (actual :: Unit)) = fromJSON $ object [ ]+ expected @=? actual+ ]+ testsToSchema = testGroup "ToSchema" [+ testCase "Normal mode" $ do + let expected = NamedSchema Nothing $ mempty & type_ .~ SwaggerObject+ let actual = toNamedSchema (Proxy :: Proxy Unit)+ expected @=? actual+ ]+ withFieldProps :: TestTree withFieldProps = testGroup "withField properties" [ functorProps@@ -343,3 +386,13 @@ where functorProps = QC.testProperty "fmap id == id" $ \(wf :: OnlyField "id" TestObj) -> fmap id wf == wf++unitDataProps :: TestTree +unitDataProps = testGroup "Unit properties" [+ parseProps+ ]+ where + parseProps = QC.testProperty "parseJSON Unit not fails" $ \(json :: Value) -> + case fromJSON json of + A.Success Unit -> True + _ -> False