{-# LANGUAGE RankNTypes #-}
module Data.Aeson.Extra.Merge (
merge,
mergeA,
lodashMerge,
ValueF(..),
ObjectF,
ArrayF,
) where
import Prelude ()
import Prelude.Compat
import Data.Aeson.Compat
import Data.Aeson.Extra.Recursive
import Data.These (These (..))
import Data.Align (alignWith)
import Data.Functor.Foldable (project, embed)
merge :: (forall a. (a -> a -> a) -> ValueF a -> ValueF a -> ValueF a)
-> Value -> Value -> Value
merge f a b = embed $ f (merge f) (project a) (project b)
mergeA :: Functor f
=> (forall a. (a -> a -> f a) -> ValueF a -> ValueF a -> f (ValueF a))
-> Value -> Value -> f Value
mergeA f a b = embed <$> f (mergeA f) (project a) (project b)
lodashMerge :: Value -> Value -> Value
lodashMerge = merge alg
where
alg :: (a -> a -> a) -> ValueF a -> ValueF a -> ValueF a
alg r a' b' = case (a', b') of
(ObjectF a, ObjectF b) -> ObjectF $ alignWith f a b
(ArrayF a, ArrayF b) -> ArrayF $ alignWith f a b
(_, b) -> b
where
f (These x y) = r x y
f (This x) = x
f (That x) = x