
Hello, i'm trying to implement this code which works but I would like to have advices to refactor this code to be more functionnal. This code receives an http request such as get?tab=urds,json={...}, converts the string json to a json structure. Then it translates it to an sqlite3 requests and sends back a json structure. since i will have several tables (urds, labos ... an so on ) i don't believe this code is optimal. there's a bunch of "case ..." that i really dislike. Though i know that i may try use ReadT monad, i don't really know how to use it with HDBCerrorhandler. here is the code: thank you for your help. ================ import Network.CGI import Database.HDBC import Database.HDBC.Sqlite3 import Data.Maybe (fromJust) import Library import Text.JSON import Control.Applicative data UrdTyp = UrdVal { urdID::String, urd::String, urdlaboID::String } deriving (Eq,Show) data LaboTyp = LaboVal { laboID::String, labo::String } deriving (Eq,Show) instance JSON UrdTyp where showJSON urds = makeObj [("urdID", showJSON $ urdID urds) ,("urd", showJSON $ urd urds) ,("laboID", showJSON $ urdlaboID urds)] readJSON urds = do obj <- readJSON urds UrdVal <$> valFromObj "urdID" obj <*> valFromObj "urd" obj <*> valFromObj "laboID" obj instance JSON LaboTyp where showJSON labos = makeObj [("laboID", showJSON $ laboID labos) ,("labo", showJSON $ labo labos)] readJSON labos = do obj <- readJSON labos LaboVal <$> valFromObj "laboID" obj <*> valFromObj "labo" obj sql2UrdVal::[(String,SqlValue)]->Maybe UrdTyp sql2UrdVal = toUrdVal . map (\(x,y)-> (x,fromSql y::String)) where toUrdVal obj= UrdVal <$> lookup "UrdID" obj <*> lookup "Urd" obj <*> lookup "LaboID" obj sql2LaboVal::[(String,SqlValue)]->Maybe LaboTyp sql2LaboVal = toLaboVal . map (\(x,y)-> (x,fromSql y::String)) where toLaboVal obj= LaboVal <$> lookup "LaboID" obj <*> lookup "Labo" obj sqlReadAll :: String ->IO [[(String,SqlValue)]] sqlReadAll table = do handle <- connectSqlite3 "fm.db" stmt <- prepare handle $ "SELECT * FROM " ++ table execute stmt [] entryRows <- fetchAllRowsAL' stmt disconnect handle return entryRows sqlReadOne:: String -> String -> Int -> IO [[(String,SqlValue)]] sqlReadOne table column eid = do handle <- connectSqlite3 "fm.db" stmt <- prepare handle $ "SELECT * FROM " ++ table ++ " where " ++ column ++" = ?" execute stmt [toSql eid] entryRows <- fetchAllRowsAL' stmt disconnect handle return entryRows queryAll:: CGI CGIResult queryAll = do Just table <- getInput "tab" entryRows <- liftIO $sqlReadAll table case table of "urds" -> do let sqlUrds = map sql2UrdVal entryRows let listUrds=map (encode.showJSON.fromJust) sqlUrds let toStr=foldr (\a b -> a++","++b) [] listUrds setHeader "Content-type" "application/x-javascript" output $ "{\"list\":" ++ "[" ++ toStr ++ "]" ++ "}" "labos" -> do let sqlLabos = map sql2LaboVal entryRows let listLabos=map (encode.showJSON.fromJust) sqlLabos let toStr=foldr (\a b -> a++","++b) [] listLabos setHeader "Content-type" "application/x-javascript" output $ "{\"list\":" ++ "[" ++ toStr ++ "]" ++ "}" queryOne:: CGI CGIResult queryOne = do jsonString <- getInput "json" Just table <- getInput "tab" case table of "urds" -> do let (Ok j) = (decode.fromJust) jsonString::Result UrdTyp let idjson = (read.urdID) j ::Int entryRows <- liftIO $sqlReadOne "urds" "urdID" idjson let sqlUrds = map sql2UrdVal entryRows let val=head.map (encode.showJSON.fromJust) $sqlUrds setHeader "Content-type" "application/x-javascript" output $"{\"data\":"++ val ++"}" "labos" -> do let (Ok j) = (decode.fromJust) jsonString::Result LaboTyp let idjson = (read.laboID) j ::Int entryRows <- liftIO $sqlReadOne "labos" "laboID" idjson let sqlLabos = map sql2LaboVal entryRows let val=head.map (encode.showJSON.fromJust) $sqlLabos setHeader "Content-type" "application/x-javascript" output $"{\"data\":"++ val ++"}" addEntrySql :: CGI CGIResult addEntrySql = do jsonString<- getInput "json" Just table <- getInput "tab" case table of "urds" -> do let (Ok j) = (decode.fromJust) jsonString::Result UrdTyp dbh <- liftIO $ connectSqlite3 "fm.db" adEJson <-liftIO $ addUrd dbh j liftIO $ commit dbh liftIO $ disconnect dbh setHeader "Content-type" "application/x-javascript" output $ "{\"entry\": " ++ "\"added\"" ++",\n\"data\": "++ encode adEJson ++"}" "labos" -> do let (Ok j) = (decode.fromJust) jsonString::Result LaboTyp dbh <- liftIO $ connectSqlite3 "fm.db" adEJson <-liftIO $ addLabo dbh j liftIO $ commit dbh liftIO $ disconnect dbh setHeader "Content-type" "application/x-javascript" output $ "{\"entry\": " ++ "\"added\"" ++",\n\"data\": " ++ encode adEJson ++"}" addUrd :: (IConnection conn) => conn -> UrdTyp -> IO UrdTyp addUrd dbh urdJs = handleSql errorHandler $ do run dbh "insert into urds (urd,LaboID) values (?,?)" $ map toSql [urd urdJs, urdlaboID urdJs] r <- quickQuery' dbh "select urdID from urds where urd=?" [toSql (urd urdJs)] case r of [[x]] -> return urdJs {urdID= fromSql x} y -> fail $ "addentry: unexpected result: " ++ show y where errorHandler e = do fail $ "problem addentry: "++ show e addLabo :: (IConnection conn) => conn -> LaboTyp -> IO LaboTyp addLabo dbh laboJs = handleSql errorHandler $ do run dbh "insert into labos (labo) values (?)" $ map toSql [labo laboJs] r <- quickQuery' dbh "select laboID from labos where labo=?" [toSql (labo laboJs)] case r of [[x]] -> return laboJs {laboID= fromSql x} y -> fail $ "addentry: unexpected result: " ++ show y where errorHandler e = do fail $ "problem addentry: "++ show e updateEntrySql :: CGI CGIResult updateEntrySql = do jsonString<- getInput "json" Just table <- getInput "tab" case table of "urds" -> do let (Ok j) = (decode.fromJust) jsonString::Result UrdTyp let entryId = urdID j dbh <- liftIO $ connectSqlite3 "fm.db" liftIO $ updateUrd dbh j entryId liftIO $ commit dbh liftIO $ disconnect dbh setHeader "Content-type" "application/x-javascript" output $ "{\"entry\": " ++ "\"modified\"" ++"}" "labos" -> do let (Ok j) = (decode.fromJust) jsonString::Result LaboTyp let entryId = laboID j dbh <- liftIO $ connectSqlite3 "fm.db" liftIO $ updateLabo dbh j entryId liftIO $ commit dbh liftIO $ disconnect dbh setHeader "Content-type" "application/x-javascript" output $ "{\"entry\": " ++ "\"modified\"" ++"}" updateUrd :: (IConnection conn) => conn -> UrdTyp -> String -> IO () updateUrd dbh urdJs entryId = handleSql errorHandler $ do r <- quickQuery' dbh "select urdID from urds where urdID=?" [toSql entryId] case r of [[x]] -> run dbh "UPDATE urds SET urd=?, laboID=? WHERE urdID=?" (map toSql [urd urdJs, urdlaboID urdJs, entryId]) >> return () y -> fail $ "updateUrd: no such urdID : " ++ show y where errorHandler e = do fail $ "problem updateUrd: "++ show e updateLabo :: (IConnection conn) => conn -> LaboTyp -> String -> IO () updateLabo dbh laboJs entryId = handleSql errorHandler $ do r <- quickQuery' dbh "select laboID from labos where laboID=?" [toSql entryId] case r of [[x]] -> run dbh "UPDATE labos SET labo=? WHERE laboID=?" (map toSql [labo laboJs, entryId]) >> return () y -> fail $ "updateLabo: no such laboID : " ++ show y where errorHandler e = do fail $ "problem updatelabo: "++ show e removeEntrySql :: CGI CGIResult removeEntrySql = do jsonString<- getInput "json" Just table <- getInput "tab" case table of "urds" -> do let (Ok j) = (decode.fromJust) jsonString::Result UrdTyp dbh <- liftIO $ connectSqlite3 "fm.db" liftIO $ removeUrd dbh (read(urdID j)::Int) liftIO $ commit dbh liftIO $ disconnect dbh setHeader "Content-type" "application/x-javascript" output $ "{\"entry\": " ++ "\"deleted\"" ++",\n\"EntryId\": "++ show (urdID j) ++"}" "labos" -> do let (Ok j) = (decode.fromJust) jsonString::Result LaboTyp dbh <- liftIO $ connectSqlite3 "fm.db" liftIO $ removeLabo dbh (read(laboID j)::Int) liftIO $ commit dbh liftIO $ disconnect dbh setHeader "Content-type" "application/x-javascript" output $ "{\"entry\": " ++ "\"deleted\"" ++",\n\"EntryId\": "++ show (laboID j) ++"}" removeUrd :: (IConnection conn) => conn -> Int -> IO () removeUrd dbh entryId = handleSql errorHandler $ do r <- quickQuery' dbh "select urdID from urds where urdID=?" [toSql entryId] case r of [[x]] -> run dbh "DELETE FROM urds WHERE urdID=?" [toSql (entryId)] >> return () y -> fail $ "removeUrd: no such urdID : " ++ show y where errorHandler e = do fail $ "problem removeUrd: "++ show e removeLabo :: (IConnection conn) => conn -> Int -> IO () removeLabo dbh entryId = handleSql errorHandler $ do r <- quickQuery' dbh "select LaboID from labos where laboID=?" [toSql entryId] case r of [[x]] -> run dbh "DELETE FROM labos WHERE laboID=?" [toSql (entryId)] >> return () y -> fail $ "removeLabo: no such laboID : " ++ show y where errorHandler e = do fail $ "problem removeLabo: "++ show e queryCommand :: CGI CGIResult queryCommand = do commandString <- getInput "command" case (fromJust commandString) of "Get" -> queryOne "GetAll" -> queryAll "AddEntry" -> addEntrySql "Modify" -> updateEntrySql "Remove" -> removeEntrySql _ -> do setHeader "Content-type" "application/x-javascript" output $ "{\"command\":\"rien compris du tout\"}" main = runCGI (handleErrors queryCommand )