module Network.Shopify.Metafield (
MetaFields, MetaValue(..), MetaNamespace
, emptyMeta, setMeta, lookupMeta, lookupMetaString
) where
import Control.Monad
import qualified Data.Text as T
import Data.Aeson ((.:), (.=))
import qualified Data.Aeson as JS
import qualified Data.Aeson.Types as JS
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HMap
import qualified Data.Vector as V
type MetaNamespace = T.Text
data MetaValue =
MetaString T.Text
| MetaInt Integer
deriving (Show)
newtype MetaFields =
MetaFields { unMetaField :: HashMap MetaNamespace (HashMap T.Text MetaValue) }
deriving (Show)
emptyMeta :: MetaFields
emptyMeta = MetaFields HMap.empty
setMeta :: MetaNamespace -> T.Text -> MetaValue -> MetaFields -> MetaFields
setMeta ns key val = MetaFields . HMap.insertWith HMap.union ns (HMap.singleton key val) . unMetaField
lookupMeta :: MetaNamespace -> T.Text -> MetaFields -> Maybe MetaValue
lookupMeta ns key = join . fmap (HMap.lookup key) . HMap.lookup ns . unMetaField
lookupMetaString :: MetaNamespace -> T.Text -> MetaFields -> Maybe T.Text
lookupMetaString ns key mf =
case lookupMeta ns key mf of
Just (MetaString s) -> Just s
_ -> Nothing
instance JS.FromJSON MetaFields where
parseJSON (JS.Array a) = do
fields <- mapM parseFields $ V.toList a
return $ foldl (\mfs (ns, k, v) -> setMeta ns k v mfs) emptyMeta fields
where
parseFields (JS.Object o) = do
ns <- o .: "namespace"
key <- o .: "key"
typ <- ((o .: "value_type")::JS.Parser String)
case typ of
"integer" -> do
i <- o .: "value"
return (ns, key, MetaInt i)
"string" -> do
s <- o .: "value"
return (ns, key, MetaString s)
_ -> mzero
parseFields _ = mzero
parseJSON _ = mzero
instance JS.ToJSON MetaFields where
toJSON =
JS.toJSON . concatMap (\(ns, nsmap) -> map (\(k, v) -> objectify ns k v) $ HMap.toList nsmap) . HMap.toList . unMetaField
where
objectify ns k (MetaString s) = JS.object ["namespace" .= ns
,"key" .= k
,"value_type" .= ("string"::T.Text)
,"value" .= s]
objectify ns k (MetaInt i) = JS.object ["namespace" .= ns
,"key" .= k
,"value_type" .= ("integer"::T.Text)
,"value" .= i]