App.hs typechecks

This commit is contained in:
Joe Nelson
2014-12-06 17:42:19 -08:00
parent 70d9641e35
commit ae9fe506be
+26 -24
View File
@@ -1,9 +1,11 @@
{-# LANGUAGE FlexibleContexts #-}
module App (app) where module App (app) where
import Control.Monad (join) import Control.Monad (join)
import Data.Monoid ( (<>) ) import Data.Monoid ( (<>) )
import Control.Arrow ((***)) import Control.Arrow ((***))
import Control.Applicative import Control.Applicative
import Control.Monad.IO.Class (liftIO, MonadIO)
import Data.Text hiding (map) import Data.Text hiding (map)
import Data.Maybe (listToMaybe, fromMaybe) import Data.Maybe (listToMaybe, fromMaybe)
@@ -31,19 +33,20 @@ import RangeQuery
import PgStructure import PgStructure
import Auth import Auth
app :: Connection -> Application app :: Request -> H.Session H.Postgres IO Response
app conn req respond = app req =
respond =<< case (path, verb) of case (path, verb) of
([], _) -> do ([], _) -> do
body <- encode <$> tables conn (cs schema) body <- H.tx Nothing $ encode <$> tables (cs schema)
return $ responseLBS status200 [jsonH] $ cs body return $ responseLBS status200 [jsonH] $ cs body
([table], "OPTIONS") -> do ([table], "OPTIONS") -> do
let t = QualifiedTable schema (cs table) let t = QualifiedTable schema (cs table)
cols <- columns conn t H.tx Nothing $ do
pkey <- map cs <$> primaryKeyColumns conn t cols <- columns t
return $ responseLBS status200 [jsonH, allOrigins] pkey <- map cs <$> primaryKeyColumns t
$ encode (TableOptions cols pkey) return $ responseLBS status200 [jsonH, allOrigins]
$ encode (TableOptions cols pkey)
([table], "GET") -> ([table], "GET") ->
if range == Just emptyRange if range == Just emptyRange
@@ -61,7 +64,7 @@ app conn req respond =
. whereT qq . whereT qq
$ selectStar qt $ selectStar qt
) )
row <- listToMaybe <$> uncurry (query conn) select row <- H.tx Nothing $ listToMaybe <$> H.list select
let (tableTotal, queryTotal, body) = let (tableTotal, queryTotal, body) =
fromMaybe (0, 0, Just "" :: Maybe ByteString) row fromMaybe (0, 0, Just "" :: Maybe ByteString) row
from = fromMaybe 0 $ rangeOffset <$> range from = fromMaybe 0 $ rangeOffset <$> range
@@ -82,26 +85,25 @@ app conn req respond =
] (cs $ fromMaybe "[]" body) ] (cs $ fromMaybe "[]" body)
(["dbapi", "users"], "POST") -> do (["dbapi", "users"], "POST") -> do
body <- strictRequestBody req body <- liftIO $ strictRequestBody req
let user = decode body :: Maybe AuthUser let user = decode body :: Maybe AuthUser
case user of case user of
Nothing -> return $ responseLBS status400 [jsonH] $ Nothing -> return $ responseLBS status400 [jsonH] $
encode . object $ [("error", String "Failed to parse user.")] encode . object $ [("error", String "Failed to parse user.")]
Just u -> do Just u -> do
_ <- addUser conn (cs $ userId u) _ <- liftIO $ addUser (cs $ userId u)
(cs $ userPass u) (cs $ userRole u) (cs $ userPass u) (cs $ userRole u)
return $ responseLBS status201 return $ responseLBS status201
[ jsonH [ jsonH
, (hLocation, "/dbapi/users?id=eq." <> cs (userId u)) , (hLocation, "/dbapi/users?id=eq." <> cs (userId u))
] "" ] ""
([table], "POST") -> ([table], "POST") ->
handleJsonObj req $ \obj -> do handleJsonObj req $ \obj -> H.tx Nothing $ do
let qt = QualifiedTable schema (cs table) let qt = QualifiedTable schema (cs table)
_ <- uncurry (execute conn) H.unit $ insertInto qt (map cs $ keys obj) (elems obj)
$ insertInto qt (map cs $ keys obj) (elems obj) primaryKeys <- map cs <$> primaryKeyColumns qt
primaryKeys <- map cs <$> primaryKeyColumns conn qt
let primaries = filterWithKey (const . (`elem` primaryKeys)) obj let primaries = filterWithKey (const . (`elem` primaryKeys)) obj
let params = urlEncodeVars let params = urlEncodeVars
$ map (\t -> (cs $ fst t, "eq." <> cs (encode $ snd t))) $ map (\t -> (cs $ fst t, "eq." <> cs (encode $ snd t)))
@@ -112,19 +114,19 @@ app conn req respond =
] "" ] ""
([table], "PUT") -> ([table], "PUT") ->
handleJsonObj req $ \obj -> do handleJsonObj req $ \obj -> H.tx Nothing $ do
let qt = QualifiedTable schema (cs table) let qt = QualifiedTable schema (cs table)
primaryKeys <- primaryKeyColumns conn qt primaryKeys <- primaryKeyColumns qt
let specifiedKeys = map (cs . fst) qq let specifiedKeys = map (cs . fst) qq
if S.fromList primaryKeys /= S.fromList specifiedKeys if S.fromList primaryKeys /= S.fromList specifiedKeys
then return $ responseLBS status405 [] then return $ responseLBS status405 []
"You must speficy all and only primary keys as params" "You must speficy all and only primary keys as params"
else do else do
tableCols <- map (cs . colName) <$> columns conn qt tableCols <- map (cs . colName) <$> columns qt
let cols = map cs $ keys obj let cols = map cs $ keys obj
if S.fromList tableCols == S.fromList cols then do if S.fromList tableCols == S.fromList cols then do
let vals = elems obj let vals = elems obj
_ <- uncurry (execute conn) $ iffNotT H.unit $ iffNotT
(whereT qq $ update qt cols vals) (whereT qq $ update qt cols vals)
(insertInto qt cols vals) (insertInto qt cols vals)
return $ responseLBS status204 [ jsonH ] "" return $ responseLBS status204 [ jsonH ] ""
@@ -135,9 +137,9 @@ app conn req respond =
"You must specify all columns in PUT request" "You must specify all columns in PUT request"
([table], "PATCH") -> ([table], "PATCH") ->
handleJsonObj req $ \obj -> do handleJsonObj req $ \obj -> H.tx Nothing $ do
let qt = QualifiedTable schema (cs table) let qt = QualifiedTable schema (cs table)
_ <- uncurry (execute conn) H.unit
$ whereT qq $ whereT qq
$ update qt (map cs $ keys obj) (elems obj) $ update qt (map cs $ keys obj) (elems obj)
return $ responseLBS status204 [ jsonH ] "" return $ responseLBS status204 [ jsonH ] ""
@@ -184,9 +186,9 @@ requestedSchema hdrs =
jsonH :: Header jsonH :: Header
jsonH = (hContentType, "application/json") jsonH = (hContentType, "application/json")
handleJsonObj :: Request -> (Object -> IO Response) -> IO Response handleJsonObj :: MonadIO m => Request -> (Object -> m Response) -> m Response
handleJsonObj req handler = do handleJsonObj req handler = do
parse <- fmap eitherDecode . strictRequestBody $ req parse <- liftIO $ fmap eitherDecode . strictRequestBody $ req
case parse of case parse of
Left err -> Left err ->
return $ responseLBS status400 [jsonH] jErr return $ responseLBS status400 [jsonH] jErr