fb 0.9.4 → 0.9.5
raw patch · 4 files changed
+65/−36 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Facebook: FQLResult :: [a] -> FQLResult a
+ Facebook: newtype FQLResult a
- Facebook: fqlQuery :: (MonadResource m, MonadBaseControl IO m) => Text -> Maybe (AccessToken anyKind) -> FacebookT anyAuth m Value
+ Facebook: fqlQuery :: (MonadResource m, MonadBaseControl IO m, FromJSON a) => Text -> Maybe (AccessToken anyKind) -> FacebookT anyAuth m a
Files
- fb.cabal +1/−1
- src/Facebook.hs +5/−0
- src/Facebook/OpenGraph.hs +50/−26
- tests/runtests.hs +9/−9
fb.cabal view
@@ -1,5 +1,5 @@ name: fb-version: 0.9.4+version: 0.9.5 license: BSD3 license-file: LICENSE author: Felipe Lessa
src/Facebook.hs view
@@ -41,10 +41,15 @@ , getUser -- * Facebook's Open Graph API+ -- ** Actions , createAction , Action+ -- ** Checkins , createCheckin+ -- ** FQL , fqlQuery+ , FQLResult(..)+ -- ** Helpers , (#=) , SimpleType(..)
src/Facebook/OpenGraph.hs view
@@ -1,17 +1,18 @@ {-# LANGUAGE FlexibleContexts, OverloadedStrings #-} module Facebook.OpenGraph ( createAction+ , Action(..) , createCheckin , fqlQuery- , Action(..)+ , FQLResult(..) , (#=) , SimpleType(..) ) where --- import Control.Applicative+import Control.Applicative ((<$>)) import Control.Arrow (first) import Control.Monad.Trans.Control (MonadBaseControl)--- import Control.Monad (mzero)+import Control.Monad (mzero) -- import Data.ByteString.Char8 (ByteString) import Data.Function (on) import Data.List (intersperse)@@ -68,30 +69,7 @@ Nothing -> post "/me/" usertoken Just apptoken -> post ("/" <> accessTokenUserId usertoken <> "/") apptoken --- | Creates a 'check-in' and returns its id. Place and--- coordinates are both required by Facebook.-createCheckin :: (C.MonadResource m, MonadBaseControl IO m) =>- Id -- ^ Place Id- -> (Double, Double) -- ^ (Latitude, Longitude)- -> [Argument] -- ^ Other arguments of the action.- -> UserAccessToken -- ^ Required user access token.- -> FacebookT Auth m Id-createCheckin pid (lat,lon) args usertoken = do- let coords = ("coordinates", toBS $ A.object ["latitude" A..= lat, "longitude" A..= lon])- body = ("place" #= pid) : coords : args- toBS = TE.encodeUtf8 . TL.toStrict . toLazyText . AE.fromValue- postObject "me/checkins" body usertoken --- | Query the Facebook Graph using FQL.-fqlQuery :: (C.MonadResource m, MonadBaseControl IO m) =>- Text -- ^ FQL Query- -> Maybe (AccessToken anyKind) -- ^ Optional access token- -> FacebookT anyAuth m A.Value-fqlQuery fql mtoken =- runResourceInFb $ do- let query = ["q" #= fql]- asJson =<< fbhttp =<< fbreq "/fql" mtoken query- -- | An action of your app. Please refer to Facebook's -- documentation at -- <https://developers.facebook.com/docs/opengraph/keyconcepts/#actions-objects>@@ -130,6 +108,52 @@ instance IsString Action where fromString = Action . fromString+++-- | Creates a 'check-in' and returns its id. Place and+-- coordinates are both required by Facebook.+createCheckin :: (C.MonadResource m, MonadBaseControl IO m) =>+ Id -- ^ Place Id+ -> (Double, Double) -- ^ (Latitude, Longitude)+ -> [Argument] -- ^ Other arguments of the action.+ -> UserAccessToken -- ^ Required user access token.+ -> FacebookT Auth m Id+createCheckin pid (lat,lon) args usertoken = do+ let coords = ("coordinates", toBS $ A.object ["latitude" A..= lat, "longitude" A..= lon])+ body = ("place" #= pid) : coords : args+ toBS = TE.encodeUtf8 . TL.toStrict . toLazyText . AE.fromValue+ postObject "me/checkins" body usertoken+++-- | Query the Facebook Graph using FQL. You may want to use+-- 'FQLResult' when parsing the returned JSON.+fqlQuery :: (C.MonadResource m, MonadBaseControl IO m, A.FromJSON a) =>+ Text -- ^ FQL Query+ -> Maybe (AccessToken anyKind) -- ^ Optional access token+ -> FacebookT anyAuth m a+fqlQuery fql mtoken =+ runResourceInFb $ do+ let query = ["q" #= fql]+ asJson =<< fbhttp =<< fbreq "/fql" mtoken query+++-- | Parses an FQL query result. FQL query results are always of the form+--+-- @+-- { "data": [ret1, ret2, ...] }+-- @+--+-- This @newtype@ unwraps the array from the @"data"@ field+-- automatically for you, so you may write something like:+--+-- @+-- FQLResult [...] <- fqlQuery ...+-- @+newtype FQLResult a = FQLResult [a] deriving (Eq, Ord, Show, Read)++instance A.FromJSON a => A.FromJSON (FQLResult a) where+ parseJSON (A.Object v) = FQLResult <$> (v A..: "data")+ parseJSON _ = mzero -- | Create an 'Argument' with a 'SimpleType'. See the docs on
tests/runtests.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings, Rank2Types #-} import Control.Applicative+import Control.Monad (mzero) import Control.Monad.IO.Class (MonadIO(liftIO)) import Control.Monad.Trans.Class (lift) import Data.Int (Int8, Int16, Int32)@@ -22,7 +23,7 @@ import qualified Facebook as FB import qualified Network.HTTP.Conduit as H -import Test.HUnit ((@?=), assertFailure)+import Test.HUnit ((@?=)) import Test.Hspec.Monadic import Test.Hspec.QuickCheck import Test.Hspec.HUnit ()@@ -147,14 +148,13 @@ describe' "fqlQuery" $ do it "is able to query Facebook's page name from its page id" $ runNoAuth $ do- A.Object obj <- FB.fqlQuery "SELECT name FROM page WHERE page_id = 20531316728" Nothing- let mr = flip A.parseMaybe () $ const r- r = do- dataArray <- obj A..: "data"- (head dataArray) A..: "name"- case mr of- Nothing -> liftIO $ assertFailure "Could not parse FQL query response."- Just r' -> r' &?= ("Facebook" :: Text)+ r <- FB.fqlQuery "SELECT name FROM page WHERE page_id = 20531316728" Nothing+ r &?= FB.FQLResult [PageName "Facebook"]++newtype PageName = PageName Text deriving (Eq, Show)+instance A.FromJSON PageName where+ parseJSON (A.Object v) = PageName <$> (v A..: "name")+ parseJSON _ = mzero libraryTests :: H.Manager -> Specs