Safe Haskell | None |
---|---|
Language | Haskell2010 |
Generics.SOP.JSON
- type JsonFieldName = String
- type JsonTagName = String
- data JsonOptions = JsonOptions {}
- defaultJsonOptions :: JsonOptions
- data Tag
- = NoTag
- | Tag JsonTagName
- data JsonInfo :: [*] -> * where
- jsonInfo :: forall a. (HasDatatypeInfo a, SingI (Code a)) => Proxy a -> JsonOptions -> NP JsonInfo (Code a)
- gtoJSON :: forall a. (Generic a, HasDatatypeInfo a, All2 ToJSON (Code a)) => JsonOptions -> a -> Value
- gparseJSON :: forall a. (Generic a, HasDatatypeInfo a, All2 FromJSON (Code a)) => JsonOptions -> Value -> Parser a
- class UpdateFromJSON a where
- updateFromJSON :: Value -> Parser (a -> a)
- gupdateFromJSON :: forall a xs. (Generic a, HasDatatypeInfo a, All UpdateFromJSON xs, Code a ~ `[xs]`) => JsonOptions -> Value -> Parser (a -> a)
- replaceWithJSON :: FromJSON a => Value -> Parser (a -> a)
- parseWith :: UpdateFromJSON a => a -> Value -> Parser a
- class ToJSON a where
- class FromJSON a where
- data Proxy t :: k -> * = Proxy
Configuration
type JsonFieldName = String Source
type JsonTagName = String Source
data JsonOptions Source
JSON encoder/decoder configuration
Constructors
JsonOptions | |
Fields
|
Instances
JSON view of a datatype
Constructor tag
For a datatype with a single constructor we do not need to tag values with their constructor; but for a datatype with multiple constructors we do.
Constructors
NoTag | |
Tag JsonTagName |
jsonInfo :: forall a. (HasDatatypeInfo a, SingI (Code a)) => Proxy a -> JsonOptions -> NP JsonInfo (Code a) Source
Generic functions
gtoJSON :: forall a. (Generic a, HasDatatypeInfo a, All2 ToJSON (Code a)) => JsonOptions -> a -> Value Source
gparseJSON :: forall a. (Generic a, HasDatatypeInfo a, All2 FromJSON (Code a)) => JsonOptions -> Value -> Parser a Source
UpdateFromJSON and co
class UpdateFromJSON a where Source
For some values we can support "updating" the value with a "partial"
JSON value; record types are the prime example (and the only one supported
by the generic function). For non-record types we typically can only
replace the value with a "complete" JSON value; in this case, we simply
ignore the old value (see replaceWithJSON
). Typical class instances will
look like
instance UpdateFromJSON SomeRecordType where updateFromJSON = gupdateFromJSON <jsonOptions>
or
instance UpdateFromJSON SomeNonRecordType where updateFromJSON = replaceWithJSON
NOTE: The generic function uses one-level lenses for the object fields. We could generalize this to arbitrary paths, but then the type would change to
updateFromJSON :: Value -> Parser (a -> UpdateM a)
I.e., updating a value from JSON would, in general, involve a database write.
Methods
updateFromJSON :: Value -> Parser (a -> a) Source
Instances
gupdateFromJSON :: forall a xs. (Generic a, HasDatatypeInfo a, All UpdateFromJSON xs, Code a ~ `[xs]`) => JsonOptions -> Value -> Parser (a -> a) Source
Construct a function that updates a value of some record type, given a JSON object with new values for some (or none, or all) of the fields
replaceWithJSON :: FromJSON a => Value -> Parser (a -> a) Source
For types that we can only replace "whole", rather than update field by field
parseWith :: UpdateFromJSON a => a -> Value -> Parser a Source
Conversely, for types that we can only parse if we have a starting point
Re-exports
class ToJSON a where
A type that can be converted to JSON.
An example type and instance:
@{-# LANGUAGE OverloadedStrings #-}
data Coord = Coord { x :: Double, y :: Double }
instance ToJSON Coord where
toJSON (Coord x y) = object
["x" .=
x, "y" .=
y]
@
Note the use of the OverloadedStrings
language extension which enables
Text
values to be written as string literals.
Instead of manually writing your ToJSON
instance, there are three options
to do it automatically:
- Data.Aeson.TH provides template-haskell functions which will derive an instance at compile-time. The generated instance is optimized for your type so will probably be more efficient than the following two options:
- Data.Aeson.Generic provides a generic
toJSON
function that accepts any type which is an instance ofData
. - If your compiler has support for the
DeriveGeneric
andDefaultSignatures
language extensions (GHC 7.2 and newer),toJSON
will have a default generic implementation.
To use the latter option, simply add a deriving
clause to your
datatype and declare a Generic
ToJSON
instance for your datatype without giving a
definition for toJSON
.
For example the previous example can be simplified to just:
@{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data Coord = Coord { x :: Double, y :: Double } deriving Generic
instance ToJSON Coord @
Note that, instead of using DefaultSignatures
, it's also possible
to parameterize the generic encoding using genericToJSON
applied
to your encoding/decoding Options
:
instance ToJSON Coord where toJSON =genericToJSON
defaultOptions
Minimal complete definition
Nothing
Instances
class FromJSON a where
A type that can be converted from JSON, with the possibility of failure.
When writing an instance, use empty
, mzero
, or fail
to make a
conversion fail, e.g. if an Object
is missing a required key, or
the value is of the wrong type.
An example type and instance:
@{-# LANGUAGE OverloadedStrings #-}
data Coord = Coord { x :: Double, y :: Double }
instance FromJSON Coord where
parseJSON (Object
v) = Coord <$>
v .:
"x" <*>
v .:
"y"
-- A non-Object
value is of the wrong type, so use mzero
to fail.
parseJSON _ = mzero
@
Note the use of the OverloadedStrings
language extension which enables
Text
values to be written as string literals.
Instead of manually writing your FromJSON
instance, there are three options
to do it automatically:
- Data.Aeson.TH provides template-haskell functions which will derive an instance at compile-time. The generated instance is optimized for your type so will probably be more efficient than the following two options:
- Data.Aeson.Generic provides a generic
fromJSON
function that parses to any type which is an instance ofData
. - If your compiler has support for the
DeriveGeneric
andDefaultSignatures
language extensions,parseJSON
will have a default generic implementation.
To use this, simply add a deriving
clause to your datatype and
declare a Generic
FromJSON
instance for your datatype without giving a definition
for parseJSON
.
For example the previous example can be simplified to just:
@{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data Coord = Coord { x :: Double, y :: Double } deriving Generic
instance FromJSON Coord @
Note that, instead of using DefaultSignatures
, it's also possible
to parameterize the generic decoding using genericParseJSON
applied
to your encoding/decoding Options
:
instance FromJSON Coord where parseJSON =genericParseJSON
defaultOptions
Minimal complete definition
Nothing
Instances
data Proxy t :: k -> *
A concrete, poly-kinded proxy type
Constructors
Proxy |
Instances
Monad (Proxy *) | |
Functor (Proxy *) | |
Applicative (Proxy *) | |
Bounded (Proxy k s) | |
Enum (Proxy k s) | |
Eq (Proxy k s) | |
Data t => Data (Proxy * t) | |
Ord (Proxy k s) | |
Read (Proxy k s) | |
Show (Proxy k s) | |
Ix (Proxy k s) | |
Generic (Proxy * t) | |
Monoid (Proxy * s) | |
Generic (Proxy * t0) | |
HasDatatypeInfo (Proxy * t0) | |
Typeable (k -> *) (Proxy k) | |
type Rep (Proxy k t) = D1 D1Proxy (C1 C1_0Proxy U1) | |
type Code (Proxy * t0) = (:) [*] ([] *) ([] [*]) |