aeson-helper-0.2.0.0: src/Data/Aeson/Helper.hs
{-# LANGUAGE OverloadedStrings #-}
module Data.Aeson.Helper
( replace
, union
, difference
, pick
) where
import Data.Aeson (Value (..))
import Data.Aeson.Key (Key, toText)
import qualified Data.Aeson.KeyMap as KeyMap (delete, difference, insert,
lookup, mapMaybeWithKey, union)
import Data.Maybe (catMaybes, fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T (isPrefixOf, stripPrefix)
import qualified Data.Vector as V (map)
-- | Replace JSON key to a new key
--
-- >>> replace "okey" "nkey" (object [ "okey" := "value" ])
-- Object (fromList [("nkey",String "value")])
--
-- >>> replace "okey" "nkey" (String "value")
-- String "value"
replace :: Key -> Key -> Value -> Value
replace okey nkey (Object v) = Object . KeyMap.insert nkey ov $ KeyMap.delete okey v
where ov = fromMaybe Null $ KeyMap.lookup okey v
replace _ _ v = v
-- | Union two JSON
--
-- >>> union (object ["key1" .= "value1"]) (object ["key2" .= "value2"])
-- Object (fromList [("key2",String "value2"),("key1",String "value1")])
--
-- >>> union (object ["key1" .= "value1"]) (object ["key1" .= "value2"])
-- Object (fromList [("key1",String "value1")])
--
-- >>> union Null (object ["key2" .= "value2"])
-- Object (fromList [("key2",String "value2")])
--
-- >>> union (object ["key1" .= "value1"]) Null
-- Object (fromList [("key1",String "value1")])
union :: Value -> Value -> Value
union (Object a) (Object b) = Object $ KeyMap.union a b
union (Object a) _ = Object a
union _ (Object b) = Object b
union _ _ = Null
-- | Difference two JSON
--
-- >>> difference (object ["key1" .= "value1", "key2" .= "value2"]) (object ["key1" .= Null])
-- Object (fromList [("key2",String "value2")])
difference :: Value -> Value -> Value
difference (Object a) (Object b) = Object $ KeyMap.difference a b
difference (Object a) _ = Object a
difference _ _ = Null
-- | Pick a value from JSON
--
-- >>> pick ["key1"] $ object ["key1" .= "value1", "key2" .= "value2", "key3" .= "value3"]
-- Object (fromList [("key1",String "value1")])
--
-- >>> pick ["key1", "key2"] $ object ["key1" .= "value1", "key2" .= "value2", "key3" .= "value3"]
-- Object (fromList [("key2",String "value2"),("key1",String "value1")])
--
-- >>> pick ["key3.key4"] $ object ["key1" .= "value1", "key2" .= "value2", "key3" .= object ["key4" .= "value4"]]
-- Object (fromList [("key3",Object (fromList [("key4",String "value4")]))])
pick :: [Text] -> Value -> Value
pick [] v = v
pick ks (Object a) = Object $ KeyMap.mapMaybeWithKey (doMapMaybeWithKey ks) a
pick ks (Array a) = Array $ V.map (pick ks) a
pick _ _ = Null
doMapMaybeWithKey :: [Text] -> Key -> Value -> Maybe Value
doMapMaybeWithKey ks key v = go ks
where go :: [Text] -> Maybe Value
go [] = Nothing
go (x:xs)
| k == x = Just v
| (k <> "." ) `T.isPrefixOf` x = Just $ pick (catMaybes $ nextKeys ks k) v
| otherwise = go xs
k = toText key
nextKeys :: [Text] -> Text -> [Maybe Text]
nextKeys [] _ = []
nextKeys (x:xs) k = T.stripPrefix (k <> ".") x : nextKeys xs k