packages feed

aeson-deriving 0.1.1.1 → 0.1.1.2

raw patch · 8 files changed

+108/−15 lines, 8 filesdep ~aesonPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependency ranges changed: aeson

API changes (from Hackage documentation)

+ Data.Aeson.Deriving.EmptyObject: EmptyObject :: a -> EmptyObject a
+ Data.Aeson.Deriving.EmptyObject: class UnitLike (f :: Type -> Type)
+ Data.Aeson.Deriving.EmptyObject: gPoint :: UnitLike f => f a
+ Data.Aeson.Deriving.EmptyObject: instance (GHC.Generics.Generic a, Data.Aeson.Deriving.EmptyObject.UnitLike (GHC.Generics.Rep a)) => Data.Aeson.Types.FromJSON.FromJSON (Data.Aeson.Deriving.EmptyObject.EmptyObject a)
+ Data.Aeson.Deriving.EmptyObject: instance Data.Aeson.Deriving.EmptyObject.UnitLike (GHC.Generics.Rep a) => Data.Aeson.Types.ToJSON.ToJSON (Data.Aeson.Deriving.EmptyObject.EmptyObject a)
+ Data.Aeson.Deriving.EmptyObject: instance Data.Aeson.Deriving.EmptyObject.UnitLike GHC.Generics.U1
+ Data.Aeson.Deriving.EmptyObject: instance Data.Aeson.Deriving.EmptyObject.UnitLike a => Data.Aeson.Deriving.EmptyObject.UnitLike (GHC.Generics.M1 GHC.Generics.C meta a)
+ Data.Aeson.Deriving.EmptyObject: instance Data.Aeson.Deriving.EmptyObject.UnitLike a => Data.Aeson.Deriving.EmptyObject.UnitLike (GHC.Generics.M1 GHC.Generics.D meta a)
+ Data.Aeson.Deriving.EmptyObject: newtype EmptyObject a

Files

ChangeLog.md view
@@ -1,10 +1,12 @@ # Changelog for aeson-deriving -# Revision history for servant-openapi+### 0.1.2 +* Added `EmptyObject` newtype for single-constructor types to be encoded as an empty JSON object.+ ### 0.1.1 -* Added newtype for Text validated against a regex pattern [PR 2](https://github.com/fieldstrength/aeson-deriving/pull/2)+* Added `TextWithPattern` newtype for Text validated against a regex pattern [PR 2](https://github.com/fieldstrength/aeson-deriving/pull/2)  ## 0.1.0 
README.md view
@@ -23,7 +23,7 @@  data User = User   { firstName :: Text-  , id_       :: UserId        +  , id_       :: UserId   , companyId :: CompanyId   }   deriving stock (Generic, Show)@@ -54,26 +54,41 @@   deriving stock (Generic, Show)   deriving (FromJSON, ToJSON) via     WithConstantFieldsOut-      '[ "version" := "1.0"-      , "system_info" := "👍" ]-        MyEncoding Transaction+     '[ "version" := "1.0"+      , "system_info" := "👍"+      ]+      (MyEncoding Transaction) ```  Note: Some newtypes that modify the instances come in an inbound and outbound variant. For example `WithConstantFields` is defined as the composition of `WithConstantFieldsIn` and `WithConstantFieldsOut`. +#### Constant Objects++Sometimes you may need an entire object of constant fields, with no information passing to the haskell representation. This is modeled as a single-value type and can also be used with the `WithConstantFields` newtype, as long as the base type is wrapped in the `EmptyObject` newtype (because otherwise unit types do not serialize to the empty object by default).++```haskell+data Requirements = Requirements+  deriving (Show, Eq, Generic)+  deriving (FromJSON, ToJSON) via+    WithConstantFields+     '[ "api_version" := "2.0"+      , "check_performed" := 'True+      ]+      (EmptyObject Requirements)+```+ #### Apply arbitrary functions before encoding/decoding  ##### Example: Special treatment for magic values  ```haskell- data Feedback = Feedback   { comment :: Text }   deriving stock (Generic, Show)   deriving (FromJSON, ToJSON) via     ModifyFieldIn "comment"       ("booo!" ==> "boo-urns!")-        MyEncoding Feedback+      (MyEncoding Feedback)   -- x ==> y  maps the value x to y and leaves others unchanged
aeson-deriving.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: afa1a88618274c13cbf349c67513735bd434bd45398e9173e13419d361544a8a+-- hash: 05a421de32621a1d52633e1311198dbc32abe2ea1f27c1e0f003d14a579b97e5  name:           aeson-deriving-version:        0.1.1.1+version:        0.1.1.2 synopsis:       data types for compositional, type-directed serialization description:    Please see the README on GitHub at <https://github.com/fieldstrength/aeson-deriving#readme> category:       Serialization@@ -36,6 +36,7 @@       Data.Aeson.Deriving.Known       Data.Aeson.Deriving.ModifyField       Data.Aeson.Deriving.SingleFieldObject+      Data.Aeson.Deriving.EmptyObject       Data.Aeson.Deriving.Utils       Data.Aeson.Deriving.WithConstantFields       Data.Aeson.Deriving.Text@@ -47,7 +48,7 @@   default-extensions: ConstraintKinds DataKinds DeriveFunctor DeriveGeneric DerivingStrategies FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving KindSignatures LambdaCase MultiParamTypeClasses NamedFieldPuns OverloadedStrings ScopedTypeVariables TupleSections TypeApplications TypeOperators   ghc-options: -Wall -Wredundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns   build-depends:-      aeson >=1.2 && <1.5+      aeson >=1.2 && <1.6     , base >=4.7 && <5     , regex-tdfa     , text@@ -64,7 +65,7 @@   default-extensions: ConstraintKinds DataKinds DeriveFunctor DeriveGeneric DerivingStrategies FlexibleContexts FlexibleInstances GeneralizedNewtypeDeriving KindSignatures LambdaCase MultiParamTypeClasses NamedFieldPuns OverloadedStrings ScopedTypeVariables TupleSections TypeApplications TypeOperators   ghc-options: -Wall -Wredundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns   build-depends:-      aeson >=1.2 && <1.5+      aeson >=1.2 && <1.6     , aeson-deriving     , base >=4.7 && <5     , hedgehog
src/Data/Aeson/Deriving.hs view
@@ -6,3 +6,4 @@ import           Data.Aeson.Deriving.SingleFieldObject  as AllExports import           Data.Aeson.Deriving.Text               as AllExports import           Data.Aeson.Deriving.WithConstantFields as AllExports+import           Data.Aeson.Deriving.EmptyObject        as AllExports
+ src/Data/Aeson/Deriving/EmptyObject.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE UndecidableInstances #-}++-- | Allow unit-like types to be serialized as the empty object+--   This can be combined with 'WithConstantFields'.+module Data.Aeson.Deriving.EmptyObject where++import Data.Aeson+import Data.Kind (Type)+import GHC.Generics++-- | For data types with exactly one value, this data type changes the serialization to be the empty JSON object.+--   It can be combined with 'WithConstantFields'.+newtype EmptyObject a = EmptyObject a++instance UnitLike (Rep a) => ToJSON (EmptyObject a) where+  toJSON _ = object []++instance (Generic a, UnitLike (Rep a)) => FromJSON (EmptyObject a) where+  parseJSON = withObject "object" $ \_hashmap ->+    pure . EmptyObject $ to gPoint+++-- | class for data types with a single constructor+class UnitLike (f :: Type -> Type) where+  gPoint :: f a++instance UnitLike U1 where+  gPoint = U1++instance UnitLike a => UnitLike (M1 C meta a) where+  gPoint = M1 gPoint++instance UnitLike a => UnitLike (M1 D meta a) where+  gPoint = M1 gPoint++
src/Data/Aeson/Deriving/Internal/Generic.hs view
@@ -5,8 +5,9 @@ module Data.Aeson.Deriving.Internal.Generic where  import           Data.Aeson-import           Data.Aeson.Deriving.Known+import           Data.Aeson.Deriving.EmptyObject        (EmptyObject(..)) import           Data.Aeson.Deriving.Internal.RecordSum+import           Data.Aeson.Deriving.Known import           Data.Aeson.Deriving.Utils import           Data.Aeson.Types                       (modifyFailure) import           Data.Char                              (isUpper, toLower, toUpper)@@ -191,6 +192,7 @@ type family LoopWarning (n :: Type -> Type) (a :: Type) :: Constraint where   LoopWarning n (GenericEncoded opts a) = ()   LoopWarning n (RecordSumEncoded tagKey tagValMod a) = ()+  LoopWarning n (EmptyObject a) = ()   LoopWarning n (DisableLoopWarning a) = ()   LoopWarning n (x & f) = LoopWarning n (f x)   LoopWarning n (f x) = LoopWarning n x
src/Data/Aeson/Deriving/WithConstantFields.hs view
@@ -49,5 +49,7 @@         flip (withObject "Object") valIn $ \obj -> do           valActual <- obj .: key           unless (valActual == valExpected) . fail $-            "Expected constant value `" <> show valExpected <> "` but got: " <>-            show valActual+            "Expected constant value " <> showEscapedJson valExpected <>+            " but got: " <> showEscapedJson valActual++      showEscapedJson val = show (encode val)
test/Main.hs view
@@ -217,3 +217,37 @@ prop_first_char_modifier_decodes_as_expected = once . property $ do   for_ [BlackHole ..] $ \x ->     tripping x encode decode+++data Unity = Unity+  deriving (Show, Eq, Generic)+  deriving (FromJSON, ToJSON) via EmptyObject Unity++prop_empty_object_encodes_as_expected :: Property+prop_empty_object_encodes_as_expected = once . property $ do+  encode Unity === "{}"++prop_empty_object_decodes_as_expected :: Property+prop_empty_object_decodes_as_expected = once . property $ tripping Unity encode decode++-- An example of how to require a particular constant object+data Requirements = Requirements+  deriving (Show, Eq, Generic)+  deriving (FromJSON, ToJSON) via+    WithConstantFields+     '[ "api_version" := "2.0"+      , "check_performed" := 'True+      ]+      (EmptyObject Requirements)++prop_constant_object_encodes_as_expected :: Property+prop_constant_object_encodes_as_expected = once . property $+  encode Requirements === "{\"api_version\":\"2.0\",\"check_performed\":true}"++prop_constant_object_decodes_as_expected :: Property+prop_constant_object_decodes_as_expected = once . property $ tripping Requirements encode decode++prop_reject_constant_object_with_incorrect_details :: Property+prop_reject_constant_object_with_incorrect_details = once . property $+  eitherDecode @Requirements "{\"api_version\":\"2.0\",\"check_performed\":false}"+    === Left "Error in $: Expected constant value \"true\" but got: \"false\""