jsonpatch-0.2.1.0: src/Data/JSON/Patch/Apply/AsValue.hs
-- |
--
-- Module : Data.JSON.Patch.Apply.AsValue
-- Copyright : (c) 2025 Patrick Brisbin
-- License : AGPL-3
-- Maintainer : pbrisbin@gmail.com
-- Stability : experimental
-- Portability : POSIX
module Data.JSON.Patch.Apply.AsValue
( PatchError (..)
, patchAsValue
) where
import Data.JSON.Patch.Prelude
import Data.Aeson (FromJSON, Result (..), ToJSON (..), Value (..), fromJSON)
import Data.Aeson.Optics (AsValue (..))
import Data.JSON.Patch.Apply
import Optics.Core
-- | A polymorphic version of 'patchValue'
--
-- The @patch@ input uses 'AsValue' from @aeson-optics@, meaning you can supply
-- a variety of types such as 'ByteString' or 'Value' and it will be parsed into
-- @['Patches']@ (capturing failure as a 'PatchError').
--
-- The @v@ input can be any domain type with JSON instances. We don't use
-- 'AsValue' here as well, even though it provides the same functionality,
-- because it's unlikely your types will have this instance.
--
-- @
-- data Person = Person
-- { name :: Text
-- , age :: Int
-- }
-- deriving stock Generic
-- deriving anyclass (FromJSON, ToJSON)
--
-- patchPersonR :: PersonId -> Handler Person
-- patchPersonR id = do
-- person <- runDB $ get id -- Person "pat" 19
-- bytes <- getRequestBody -- "[{op:replace, path:/age, value:21}]"
--
-- case patchAsValue bytes person of
-- Left err -> sendResponse 400 $ displayException err
-- Right updated -> do
-- runDB $ update id updated
-- sendResponse 200 updated -- Person "pat" 21
-- @
--
-- If the patch creates a value that can't parse back to your domain type, that
-- will also be normalized to 'PatchError'.
patchAsValue
:: (AsValue patch, FromJSON v, ToJSON v) => patch -> v -> Either PatchError v
patchAsValue p target = do
pVal <- note (ParseError Null "not JSON") $ p ^? _Value
patches <- fromJSONEither pVal
result <- patchValue patches $ toJSON target
fromJSONEither result
fromJSONEither :: FromJSON a => Value -> Either PatchError a
fromJSONEither v = case fromJSON v of
Error e -> Left $ ParseError v e
Success a -> Right a