Bring parse call into common logic.
[haskell-cryptsy-api.git] / Cryptsy / API / Public / MarketData.hs
blob9a754cc7ce2621558077ccf853649d029da6fe1f
1 {-# LANGUAGE FlexibleContexts, ViewPatterns #-}
2 module Cryptsy.API.Public.MarketData
3 ( GMarketData(..), MarketData
4 , withComponents, withMarket
5 , onMarkets, singleMarketData
6 , module Cryptsy.API.Public
7 , module Cryptsy.API.Public.Market
8 -- |Re-exported from Data.Aeson
9 , Object, FromJSON(..)
10 -- |Re-exported from Data.HashMap.Strict
11 , HashMap
13 where
15 -- aeson
16 import Data.Aeson ( FromJSON(..), Object, withObject )
18 -- base
19 import Control.Monad (fail)
20 import Data.Function (($), (.))
21 import Data.Functor (fmap, (<$>))
22 import Data.List ((++))
23 import Data.Maybe (maybe)
24 import Data.String (String)
25 import Data.Traversable (mapM)
26 import Prelude (Show(show))
28 -- text
29 import Data.Text (pack, unpack)
31 -- unordered-containers
32 import Data.HashMap.Strict (HashMap, toList)
33 import qualified Data.HashMap.Strict as HM (lookup)
35 -- this package
36 import Cryptsy.API.Public
37 import Cryptsy.API.Public.Market
38 ( GMarket(..), Market
39 -- for re-export
40 , GOrder(Order)
41 , GTrade(Trade, time)
42 , Vector
45 -- |general market data parameterized by types for prices, quantities,
46 -- date/time values, and totals (price * quantity)
47 newtype GMarketData p q dt t =
48 MarketData { markets :: HashMap Text (GMarket p q dt t) }
49 deriving Show
50 type MarketData = GMarketData CryptsyNum CryptsyNum Text CryptsyNum
52 instance (FromJSON p, FromJSON q, FromJSON dt, FromJSON t) =>
53 FromJSON (GMarketData p q dt t)
54 where
55 parseJSON = withObject "markets" $ withComponents parseJSON
57 -- |unpacked 'marketsKey'
58 marketsStr :: String
59 marketsStr = "markets"
61 -- |failure message when 'marketsKey' is missing
62 missingMsg :: String
63 missingMsg = "Missing '" ++ marketsStr ++ "' key."
65 -- |key in JSON object for market data
66 marketsKey :: Text
67 marketsKey = pack marketsStr
69 -- |Apply a parser on the 'marketsKey' of an object. If not an object or the
70 -- key is missing, fail.
71 onMarkets :: (Value -> Parser a) -> Value -> Parser a
72 onMarkets parser = withObject marketsStr $
73 maybe (fail missingMsg) parser . HM.lookup marketsKey
75 -- |Build parser for multiple markets from parser for single market.
76 withComponents :: (Value -> Parser (GMarket p q dt t)) -- ^ market parser
77 -> Object -> Parser (GMarketData p q dt t)
78 withComponents parseMarket = fmap MarketData <$> mapM parseMarket
80 -- |Build parser for multiple markets from parser for single market object.
81 withMarket :: (Object -> Parser (GMarket p q dt t)) -- ^ market parser
82 -> Object -> Parser (GMarketData p q dt t)
83 withMarket parseMarket = withComponents (withObject "market" parseMarket)
85 singleMarketData :: FromJSON (GMarket p q dt t)
86 => Text -- ^ marketid
87 -> PubCryptsy (GMarket p q dt t)
88 singleMarketData (unpack -> reqMarket) = pubCryptsy marketURL parseSingleMarket
89 where
90 marketURL = pubURL $ "singlemarketdata&marketid=" ++ reqMarket
91 parseSingleMarket = withObject "Market" $ \o ->
92 case toList o of
93 [] -> fail "No market returned."
94 [(_, v)] -> parseJSON v
95 _ -> fail "Multiple markets returned."