{-# LANGUAGE CPP #-}

-- | This module provides wrappers for compatibility between versions of @aeson@
-- prior to and after 2.0.  It is not necessarily stable.
--
module Data.API.JSON.Compat
    ( Key
    , KeyMap

    , lookupKey
    , listToObject
    , objectToList
    , matchSingletonObject
    , singletonObject
    , insertKey
    , deleteKey
    , objectToMap
    , mapToObject
    , traverseObjectWithKey
    , adjustObject

    , fieldNameToKey
    , keyToFieldName
    , textToKey
    , keyToText
    ) where

import           Data.API.Types

import qualified Data.Map.Strict                as Map
import qualified Data.Text                      as T

#if MIN_VERSION_aeson(2,0,0)

import           Data.Aeson.Key (Key)
import qualified Data.Aeson.Key                 as Key
import           Data.Aeson.KeyMap (KeyMap)
import qualified Data.Aeson.KeyMap              as KeyMap

lookupKey :: T.Text -> KeyMap a -> Maybe a
lookupKey :: Text -> KeyMap a -> Maybe a
lookupKey Text
k KeyMap a
m = Key -> KeyMap a -> Maybe a
forall v. Key -> KeyMap v -> Maybe v
KeyMap.lookup (Text -> Key
Key.fromText Text
k) KeyMap a
m

listToObject :: [(T.Text, a)] -> KeyMap a
listToObject :: [(Text, a)] -> KeyMap a
listToObject = [(Key, a)] -> KeyMap a
forall v. [(Key, v)] -> KeyMap v
KeyMap.fromList ([(Key, a)] -> KeyMap a)
-> ([(Text, a)] -> [(Key, a)]) -> [(Text, a)] -> KeyMap a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Text, a) -> (Key, a)) -> [(Text, a)] -> [(Key, a)]
forall a b. (a -> b) -> [a] -> [b]
map (\ (Text
x, a
y) -> (Text -> Key
Key.fromText Text
x, a
y))

objectToList :: KeyMap a -> [(T.Text, a)]
objectToList :: KeyMap a -> [(Text, a)]
objectToList = ((Key, a) -> (Text, a)) -> [(Key, a)] -> [(Text, a)]
forall a b. (a -> b) -> [a] -> [b]
map (\ (Key
x, a
y) -> (Key -> Text
Key.toText Key
x, a
y)) ([(Key, a)] -> [(Text, a)])
-> (KeyMap a -> [(Key, a)]) -> KeyMap a -> [(Text, a)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyMap a -> [(Key, a)]
forall v. KeyMap v -> [(Key, v)]
KeyMap.toList

matchSingletonObject :: KeyMap a -> Maybe (T.Text, a)
matchSingletonObject :: KeyMap a -> Maybe (Text, a)
matchSingletonObject KeyMap a
km = case KeyMap a -> [(Text, a)]
forall a. KeyMap a -> [(Text, a)]
objectToList KeyMap a
km of
                            [(Text
k, a
v)] -> (Text, a) -> Maybe (Text, a)
forall a. a -> Maybe a
Just (Text
k, a
v)
                            [(Text, a)]
_        -> Maybe (Text, a)
forall a. Maybe a
Nothing

singletonObject :: T.Text -> a -> KeyMap a
singletonObject :: Text -> a -> KeyMap a
singletonObject Text
k = Key -> a -> KeyMap a
forall v. Key -> v -> KeyMap v
KeyMap.singleton (Text -> Key
Key.fromText Text
k)

insertKey :: T.Text -> a -> KeyMap a -> KeyMap a
insertKey :: Text -> a -> KeyMap a -> KeyMap a
insertKey Text
k = Key -> a -> KeyMap a -> KeyMap a
forall v. Key -> v -> KeyMap v -> KeyMap v
KeyMap.insert (Text -> Key
Key.fromText Text
k)

deleteKey :: T.Text -> KeyMap a -> KeyMap a
deleteKey :: Text -> KeyMap a -> KeyMap a
deleteKey Text
k = Key -> KeyMap a -> KeyMap a
forall v. Key -> KeyMap v -> KeyMap v
KeyMap.delete (Text -> Key
Key.fromText Text
k)

objectToMap :: KeyMap a -> Map.Map T.Text a
objectToMap :: KeyMap a -> Map Text a
objectToMap = KeyMap a -> Map Text a
forall v. KeyMap v -> Map Text v
KeyMap.toMapText

mapToObject :: Map.Map T.Text a -> KeyMap a
mapToObject :: Map Text a -> KeyMap a
mapToObject = Map Text a -> KeyMap a
forall v. Map Text v -> KeyMap v
KeyMap.fromMapText

traverseObjectWithKey :: Applicative f => (T.Text -> v1 -> f v2) -> KeyMap v1 -> f (KeyMap v2)
traverseObjectWithKey :: (Text -> v1 -> f v2) -> KeyMap v1 -> f (KeyMap v2)
traverseObjectWithKey Text -> v1 -> f v2
f = (Key -> v1 -> f v2) -> KeyMap v1 -> f (KeyMap v2)
forall (f :: * -> *) v1 v2.
Applicative f =>
(Key -> v1 -> f v2) -> KeyMap v1 -> f (KeyMap v2)
KeyMap.traverseWithKey (\ Key
k -> Text -> v1 -> f v2
f (Key -> Text
Key.toText Key
k))

fieldNameToKey :: FieldName -> Key
fieldNameToKey :: FieldName -> Key
fieldNameToKey = Text -> Key
Key.fromText (Text -> Key) -> (FieldName -> Text) -> FieldName -> Key
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FieldName -> Text
_FieldName

textToKey :: T.Text -> Key
textToKey :: Text -> Key
textToKey = Text -> Key
Key.fromText

keyToFieldName :: Key -> FieldName
keyToFieldName :: Key -> FieldName
keyToFieldName = Text -> FieldName
FieldName (Text -> FieldName) -> (Key -> Text) -> Key -> FieldName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Key -> Text
Key.toText

keyToText :: Key -> T.Text
keyToText :: Key -> Text
keyToText = Key -> Text
Key.toText

adjustObject :: (v -> v) -> Key -> KeyMap v -> KeyMap v
adjustObject :: (v -> v) -> Key -> KeyMap v -> KeyMap v
adjustObject v -> v
f Key
k KeyMap v
m = case Key -> KeyMap v -> Maybe v
forall v. Key -> KeyMap v -> Maybe v
KeyMap.lookup Key
k KeyMap v
m of
                       Maybe v
Nothing -> KeyMap v
m
                       Just v
v  -> Key -> v -> KeyMap v -> KeyMap v
forall v. Key -> v -> KeyMap v -> KeyMap v
KeyMap.insert Key
k (v -> v
f v
v) KeyMap v
m

#else

import qualified Data.HashMap.Strict as HMap

type Key = T.Text

type KeyMap = HMap.HashMap Key

lookupKey :: T.Text -> KeyMap a -> Maybe a
lookupKey = HMap.lookup

listToObject :: [(T.Text, a)] -> KeyMap a
listToObject = HMap.fromList

objectToList :: KeyMap a -> [(T.Text, a)]
objectToList = HMap.toList

matchSingletonObject :: KeyMap a -> Maybe (T.Text, a)
matchSingletonObject km = case objectToList km of
                            [(k, v)] -> Just (k, v)
                            _        -> Nothing

singletonObject :: T.Text -> a -> KeyMap a
singletonObject = HMap.singleton

insertKey :: T.Text -> a -> KeyMap a -> KeyMap a
insertKey = HMap.insert

deleteKey :: T.Text -> KeyMap a -> KeyMap a
deleteKey = HMap.delete

objectToMap :: KeyMap a -> Map.Map T.Text a
objectToMap = Map.fromList . HMap.toList

mapToObject :: Map.Map T.Text a -> KeyMap a
mapToObject = HMap.fromList . Map.toList

traverseObjectWithKey :: Applicative f => (T.Text -> v1 -> f v2) -> KeyMap v1 -> f (KeyMap v2)
traverseObjectWithKey = HMap.traverseWithKey

adjustObject :: (v -> v) -> Key -> KeyMap v -> KeyMap v
adjustObject = HMap.adjust

fieldNameToKey :: FieldName -> Key
fieldNameToKey = _FieldName

keyToFieldName :: Key -> FieldName
keyToFieldName = FieldName

textToKey :: T.Text -> Key
textToKey = id

keyToText :: Key -> T.Text
keyToText = id

#endif