@@ -62,9 +62,10 @@ import qualified Fcf
6262import qualified GHC.TypeLits as Error
6363
6464
65- -- | A newtype wrapper which provides 'FromJSON' / 'ToJSON' instances with a specific set
66- -- of 'Options' (see the "Deriving.Aeson" module), and the ability to strip one or more
67- -- fields from the JSON output, recovered at decode-time using some default values.
65+ -- | A newtype wrapper which provides 'FromJSON' / 'ToJSON' instances based on a specific
66+ -- set of 'AesonOptions' (see the "Deriving.Aeson" module), and the ability to strip one
67+ -- or more fields from the JSON output, recovered when decoding using some default
68+ -- `RecoverableValue`s.
6869newtype StrippedJSON (fds :: [Type ]) (opts :: [Type ]) a
6970 = StrippedJSON { unStrippedJSON :: a }
7071
@@ -113,13 +114,13 @@ instance
113114
114115-- | A field to be stripped from record values, identified by its @name@.
115116--
116- -- The @def@ value is used to recover the field at decode-time (see 'RecoverableValue').
117+ -- The @def@ value is used to recover the field when decoding (see 'RecoverableValue').
117118data RField (name :: Symbol ) (def :: k )
118119
119120-- | A field to be stripped from non-record single-constructor values,
120121-- identified by its __zero-based__ @position@ in the data constructor.
121122--
122- -- The @def@ value is used to recover the field at decode-time (see 'RecoverableValue').
123+ -- The @def@ value is used to recover the field when decoding (see 'RecoverableValue').
123124data CField (position :: Nat ) (def :: k )
124125
125126
@@ -204,8 +205,8 @@ data FromList (xs :: [k])
204205
205206-- | Recovers a 'Monoid' value using 'mempty'.
206207--
207- -- >>> recoverValue (Proxy @(Pure 1)) :: Maybe Int
208- -- Just 1
208+ -- >>> recoverValue (Proxy @Mempty) :: [ Int]
209+ -- []
209210data Mempty
210211
211212-- | Recovers an 'Applicative' value using 'pure'.
@@ -215,7 +216,7 @@ data Mempty
215216data Pure (x :: k )
216217
217218
218- -- | A default field value which can be recovered at decode-time .
219+ -- | A default field value which can be recovered when decoding .
219220class RecoverableValue (x :: k ) (a :: Type ) where
220221 -- | Recovers a default field value from the type-level.
221222 recoverValue :: Proxy x -> a
@@ -401,6 +402,7 @@ instance Monoid m => RecoverableValue Mempty m where
401402--
402403-- >>> :set -XDataKinds
403404-- >>> :set -XDeriveGeneric
405+ -- >>> :set -XDerivingVia
404406-- >>> :set -XGeneralizedNewtypeDeriving
405407-- >>> :set -XOverloadedStrings
406408-- >>> :set -XTypeApplications
@@ -418,94 +420,82 @@ instance Monoid m => RecoverableValue Mempty m where
418420--
419421-- >>> :{
420422-- data RecordTest = RecordTest
421- -- { testNumber :: {-# UNPACK #-} !Int
423+ -- { testBool :: !Bool
424+ -- , testNumber :: {-# UNPACK #-} !Int
422425-- , testNewtype :: !WrappedInt
423426-- , testString :: String
424427-- , testIsString :: !Text
425428-- , testList :: ![Int]
426- -- , testIsList :: (Set.Set Int)
427- -- , testMonoid :: ![Int]
429+ -- , testIsList :: Set.Set Int
430+ -- , testMonoid :: !Ordering
431+ -- , testValue :: Double
428432-- }
429433-- deriving (Generic, Show)
434+ -- deriving (FromJSON, ToJSON)
435+ -- via StrippedJSON
436+ -- '[ RField "testBool" 'False
437+ -- , RField "testIsList" (FromList '[ 13, 14, 13 ])
438+ -- , RField "testIsString" (FromString "text")
439+ -- , RField "testList" '[ 10, 11, 12 ]
440+ -- , RField "testMonoid" Mempty
441+ -- , RField "testNewtype" (Coerce 42 Int)
442+ -- , RField "testNumber" 7
443+ -- , RField "testString" "string"
444+ -- ]
445+ -- '[]
446+ -- RecordTest
430447-- :}
431448--
432- -- >>> :{
433- -- type StrippedRecordFields =
434- -- '[ RField "testNumber" 7
435- -- , RField "testNewtype" (Coerce 42 Int)
436- -- , RField "testString" "string"
437- -- , RField "testIsString" (FromString "text")
438- -- , RField "testList" '[ 10, 11, 12 ]
439- -- , RField "testIsList" (FromList '[ 13, 14, 13 ])
440- -- , RField "testMonoid" Mempty
441- -- ]
442- -- :}
449+ -- Note that the order of the `RField` instructions does not matter ..
450+ --
451+ -- >>> let recordTest = RecordTest True 1 (WrappedInt 2) "s" "t" [1..3] (Set.fromList [4..6]) GT 3.14
443452--
444453-- >>> :{
445454-- data NonRecordTest
446- -- = NonRecordTest (Either String Int) (Maybe Int) ![Int] (Bool, Char, Int)
455+ -- = NonRecordTest () ( Either String Int) (Maybe Int) ![Int] (Bool, Char, Int)
447456-- deriving (Generic, Show)
457+ -- deriving (FromJSON, ToJSON)
458+ -- via StrippedJSON
459+ -- '[ CField 0 '()
460+ -- , CField 1 ('Left "test")
461+ -- , CField 3 (Pure 7)
462+ -- , CField 2 'Nothing
463+ -- , CField 4 '( 'False, "z", 42 )
464+ -- ]
465+ -- '[]
466+ -- NonRecordTest
448467-- :}
449468--
450- -- >>> :{
451- -- type StrippedNonRecordFields =
452- -- '[ CField 0 ('Left "test")
453- -- , CField 2 (Pure 7)
454- -- , CField 1 'Nothing
455- -- , CField 3 '( 'False, "z", 42 )
456- -- ]
457- -- :}
469+ -- .. nor does the order of the `CField` instructions.
470+ --
471+ -- >>> let nonRecordTest = NonRecordTest () (Right 1) (Just 2) [3..5] (True, 'a', 6)
458472
459473-- $examples
460474--
461475-- === Stripping fields in a record value: ..
462476--
463- -- >>> :{
464- -- encode
465- -- $ StrippedJSON @StrippedRecordFields @'[]
466- -- $ RecordTest 1 (WrappedInt 2) "s" "t" [1..3] (Set.fromList [4..6]) [7..9]
467- -- :}
468- -- "[]"
477+ -- >>> encode recordTest
478+ -- "{\"testValue\":3.14}"
469479--
470480-- === .. and recovering them when decoding using the specified defaults:
471481--
472- -- >>> :{
473- -- fmap unStrippedJSON
474- -- $ decode @(StrippedJSON StrippedRecordFields '[] RecordTest)
475- -- $ encode
476- -- $ StrippedJSON @StrippedRecordFields @'[]
477- -- $ RecordTest 1 (WrappedInt 2) "s" "t" [1..3] (Set.fromList [4..6]) [7..9]
478- -- :}
479- -- Just (RecordTest {testNumber = 7, testNewtype = WrappedInt 42, testString = "string", testIsString = "text", testList = [10,11,12], testIsList = fromList [13,14], testMonoid = []})
482+ -- >>> decode @RecordTest $ encode recordTest
483+ -- Just (RecordTest {testBool = False, testNumber = 7, testNewtype = WrappedInt 42, testString = "string", testIsString = "text", testList = [10,11,12], testIsList = fromList [13,14], testMonoid = EQ, testValue = 3.14})
480484--
481485-- === Stripping fields in a non-record value: ..
482- -- >>> :{
483- -- encode
484- -- $ StrippedJSON @StrippedNonRecordFields @'[]
485- -- $ NonRecordTest (Right 1) (Just 2) [3..5] (True, 'a', 6)
486- -- :}
486+ -- >>> encode nonRecordTest
487487-- "[]"
488488--
489489-- === .. and recovering them when decoding using the specified defaults:
490490--
491- -- >>> :{
492- -- fmap unStrippedJSON
493- -- $ decode @(StrippedJSON StrippedNonRecordFields '[] NonRecordTest)
494- -- $ encode
495- -- $ StrippedJSON @StrippedNonRecordFields @'[]
496- -- $ NonRecordTest (Right 1) (Just 2) [3..5] (True, 'a', 6)
497- -- :}
498- -- Just (NonRecordTest (Left "test") Nothing [7] (False,'z',42))
491+ -- >>> decode @NonRecordTest $ encode nonRecordTest
492+ -- Just (NonRecordTest () (Left "test") Nothing [7] (False,'z',42))
499493--
500494-- === Specifying encoding / decoding options:
501495--
502496-- The second parameter to 'StrippedJSON' works exactly the same as the only parameter
503- -- to 'CustomJSON' ( from the
504- -- [deriving-aeson](http://hackage.haskell.org/package/deriving-aeson) package) .
497+ -- to 'CustomJSON' from the
498+ -- [deriving-aeson](http://hackage.haskell.org/package/deriving-aeson) package.
505499--
506- -- >>> :{
507- -- encode
508- -- $ StrippedJSON @'[] @'[ FieldLabelModifier CamelToSnake ]
509- -- $ RecordTest 1 (WrappedInt 2) "s" "t" [1..3] (Set.fromList [4..6]) [7..9]
510- -- :}
511- -- "{\"test_number\":1,\"test_newtype\":2,\"test_string\":\"s\",\"test_is_string\":\"t\",\"test_list\":[1,2,3],\"test_is_list\":[4,5,6],\"test_monoid\":[7,8,9]}"
500+ -- >>> encode $ StrippedJSON @'[] @'[ FieldLabelModifier CamelToSnake ] recordTest
501+ -- "{\"test_bool\":true,\"test_number\":1,\"test_newtype\":2,\"test_string\":\"s\",\"test_is_string\":\"t\",\"test_list\":[1,2,3],\"test_is_list\":[4,5,6],\"test_monoid\":\"GT\",\"test_value\":3.14}"
0 commit comments