prairie-0.1.0.0: src/Prairie/Update.hs
-- | This cl
--
-- @since 0.0.1.0
module Prairie.Update where
import Data.Aeson (FromJSON (..), ToJSON (..), object, withObject, (.:), (.=))
import Data.Typeable (Typeable, eqT, (:~:) (..))
import Prairie.Class
import Prairie.Internal (set)
-- | An operation representing an update against the 'rec' in question.
--
-- This type is partially an example - you may want to have a more
-- sophisticated update type than merely setting fields.
--
-- @since 0.0.1.0
data Update rec where
SetField :: Field rec a -> a -> Update rec
-- |
--
-- @since 0.0.1.0
instance
(forall a. Eq (Field rec a), FieldDict Typeable rec, FieldDict Eq rec)
=> Eq (Update rec)
where
SetField f0 (a0 :: a0) == SetField f1 (a1 :: a1) =
withFieldDict @Typeable f0 $
withFieldDict @Typeable f1 $
case eqT @a0 @a1 of
Nothing ->
False
Just Refl ->
withFieldDict @Eq f0 $
f0 == f1 && a0 == a1
-- |
--
-- @since 0.0.1.0
instance (forall a. Show (Field rec a), FieldDict Show rec) => Show (Update rec) where
showsPrec d (SetField field a) =
withFieldDict @Show field $
showParen (d > 10) $
showString "Update "
. showsPrec 11 field
. showString " "
. showsPrec 11 a
-- | Renders an 'Update' in the following format:
--
-- @
-- {
-- "field": 'toJSON' field,
-- "value": 'toJSON' newValue
--
-- }
-- @
--
-- @since 0.0.1.0
instance (FieldDict ToJSON rec, forall a. ToJSON (Field rec a)) => ToJSON (Update rec) where
toJSON (SetField field newVal) =
withFieldDict @ToJSON field $
object ["field" .= field, "value" .= newVal]
-- | Parses an 'Update' with the following format:
--
-- @
-- {
-- "field": field,
-- "value": newValue
-- }
-- @
--
--
-- @since 0.0.1.0
instance
(FieldDict FromJSON rec, FieldDict Typeable rec, FromJSON (SomeField rec))
=> FromJSON (Update rec)
where
parseJSON = withObject "Update" $ \o -> do
field <- o .: "field"
case field of
SomeField field ->
withFieldDict @FromJSON field $
SetField field <$> o .: "value"
-- | Run an 'Update' against the record it is for.
--
-- @
-- >>> let user = User { name = \"Bob\", age = 30 }
-- >>> updateSingleField (SetField UserName "Alice") user
-- User { name = \"Alice\", age = 30 }
-- @
--
-- @since 0.0.1.0
updateSingleField :: (Record rec) => Update rec -> rec -> rec
updateSingleField (SetField field newValue) rec =
set (recordFieldLens field) newValue rec
-- | Perform an list of updates against the 'Record'.
--
-- @since 0.0.1.0
updateRecord :: (Record rec) => [Update rec] -> rec -> rec
updateRecord upds rec = foldr updateSingleField rec upds