yesod-dsl-0.1.1.23: YesodDsl/Generator/UpdateHandlers.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
module YesodDsl.Generator.UpdateHandlers where
import YesodDsl.AST
import Data.Maybe
import qualified Data.Text as T
import Data.List
import Text.Shakespeare.Text hiding (toText)
import Data.String.Utils (rstrip)
import YesodDsl.Generator.Esqueleto
import YesodDsl.Generator.Common
import YesodDsl.Generator.Models
import YesodDsl.Generator.Require
import YesodDsl.Generator.Input
import Control.Monad.State
import qualified Data.Map as Map
updateHandlerRunDB :: (Int,HandlerParam) -> State Context String
updateHandlerRunDB (pId,p) = liftM concat $ sequence ([
updateHandlerDecode (pId,p) >>= return . (indent 4),
case p of
GetById en fr vn -> do
ifr <- inputFieldRef fr
return $ T.unpack $(codegenFile "codegen/get-by-id.cg")
Update en fr io -> do
ifr <- inputFieldRef fr
return $ T.unpack $(codegenFile "codegen/replace.cg")
Insert en io mbv -> do
return $ T.unpack $(codegenFile "codegen/insert.cg")
where
maybeBindResult (Just vn) = "result_" ++ vn ++ " <- "
maybeBindResult _ = ""
DeleteFrom en vn Nothing -> return $
let maybeExpr = rstrip $ T.unpack $(codegenFile "codegen/delete-all.cg")
in T.unpack $(codegenFile "codegen/delete.cg")
DeleteFrom en vn (Just e) -> do
withScope [(en,vn,False)] $ do
maybeExpr <- hsBoolExpr e
return $ T.unpack $(codegenFile "codegen/delete.cg")
For vn fr hps -> do
content <- liftM concat $ mapM updateHandlerRunDB $
zip [1..] hps
ifr <- inputFieldRef fr
return $ T.unpack $(codegenFile "codegen/for.cg")
Call fn frs -> do
ifrs <- mapM inputFieldRef frs
return $ T.unpack $(codegenFile "codegen/call.cg")
_ -> return ""
] :: [State Context String])
defaultFieldValue :: Field -> String
defaultFieldValue f = case fieldDefault f of
Just fv -> fieldValueToHs fv
Nothing -> if fieldOptional f
then "Nothing"
else let fn = fieldName f in T.unpack $(codegenFile "codegen/map-input-field-normal.cg")
addCtxType :: InputFieldRef -> TypeName -> State Context ()
addCtxType ifr typeName = do
ctx <- get
put $ ctx { ctxTypes = Map.insert ifr typeName $ ctxTypes ctx }
mapJsonInputField :: [InputField] -> Bool -> (Entity,Field) -> State Context (Maybe String)
mapJsonInputField ifields isNew (e,f) = do
mcontent <- mkContent
case mcontent of
Just content' -> do
let content = rstrip content'
return $ Just $ T.unpack $(codegenFile "codegen/map-input-field.cg")
Nothing -> return Nothing
where
maybeJust :: Bool -> String -> String
maybeJust True v = "(Just " ++ v ++ ")"
maybeJust False v = v
maybeInput = matchInputField ifields (fieldName f)
notNothing = case maybeInput of
Just (InputFieldConst NothingValue, _) -> False
_ -> True
notInputField = case maybeInput of
Just (InputFieldNormal _, _) -> False
_ -> True
promoteJust = fieldOptional f && isJust maybeInput && notNothing && notInputField
mapper mmapper = maybe "" ((" $ " ++) . (++ " $ ")) mmapper
mkContent = case maybeInput of
Just (ifr@(InputFieldNormal fn), mm) -> do
addCtxType ifr (hsFieldType f)
return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/map-input-field-normal.cg")
Just (InputFieldAuthId, mm) -> return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/map-input-field-authid.cg")
Just (InputFieldAuth fn, mm) -> return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/map-input-field-auth.cg")
Just (InputFieldPathParam i, mm) -> return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/map-input-field-pathparam.cg")
Just (InputFieldConst v, mm) -> return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/map-input-field-const.cg")
Just (InputFieldNow, mm) -> return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/map-input-field-now.cg")
Just (InputFieldLocalParam vn, mm) -> return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/map-input-field-localparam.cg")
Just (InputFieldLocalParamField vn fn, mm) -> do
ps <- gets ctxHandlerParams
let en = fromJust $ listToMaybe $ concatMap f ps
return $ Just $ mapper mm ++ T.unpack $(codegenFile "codegen/input-field-local-param-field.cg")
where
f (GetById en _ vn') = if vn' == vn then [en] else []
f _ = []
Just (InputFieldCheckmark v, mm) -> return $ Just $ mapper mm ++ case v of
CheckmarkActive -> "Active"
CheckmarkInactive -> "Inactive"
Nothing -> return $ if isNew then Just $ defaultFieldValue f
else Nothing
matchInputField :: [InputField] -> FieldName -> Maybe (InputFieldRef, Maybe FunctionName)
matchInputField ifields fn = listToMaybe [ (inp,mm) | (pn,inp,mm) <- ifields, pn == fn ]
prepareJsonInputField :: FieldName -> String
prepareJsonInputField fn = T.unpack $(codegenFile "codegen/prepare-input-field-normal.cg")
updateHandlerDecode :: (Int,HandlerParam) -> State Context String
updateHandlerDecode (pId,p) = case p of
Update en fr io -> do
m <- gets ctxModule
readInputObject (fromJust $ lookupEntity m en) (io >>= \io' -> Just (Nothing, io')) (Just fr)
Insert en io _ -> do
m <- gets ctxModule
readInputObject (fromJust $ lookupEntity m en) io Nothing
_ -> return ""
where
readInputObject :: Entity -> Maybe (Maybe VariableName, [InputField]) -> Maybe InputFieldRef -> State Context String
readInputObject e (Just (mv, fields)) fr = do
maybeExisting <- maybeSelectExisting e (mv,fields) fr
fieldMappers <- mapFields e fields isNew
return $ T.unpack $(codegenFile "codegen/read-input-object-fields.cg")
where
isNew = isNothing fr && isNothing mv
entityToUpdate
| isNew = entityName e
| otherwise = "e"
readInputObject e Nothing _ = do
fieldMappers <- mapFields e [] True
return $ T.unpack $(codegenFile "codegen/read-input-object-whole.cg")
maybeSelectExisting e (Nothing, fields) (Just fr)
| Nothing `elem` [ matchInputField fields (fieldName f)
| f <- entityFields e ] = do
ifr <- inputFieldRef fr
return $ T.unpack $(codegenFile "codegen/select-existing.cg")
| otherwise = return ""
maybeSelectExisting _ (Just vn, _) _ = return $ T.unpack $(codegenFile "codegen/select-bound-result.cg")
maybeSelectExisting e _ _ = return ""
mapFields e fields isNew = liftM ((intercalate ",\n") . catMaybes) $ mapM (mapJsonInputField fields isNew)
[ (e,f) | f <- entityFields e ]
updateHandlerReadJsonFields :: State Context String
updateHandlerReadJsonFields = do
m <- gets ctxModule
ps <- gets ctxHandlerParams
let attrs = jsonAttrs m ps
if null attrs
then return ""
else return $
(T.unpack $(codegenFile "codegen/json-body.cg"))
++ concatMap prepareJsonInputField attrs
where
jsonAttrs m ps = nub $ concatMap (getJsonAttrs m) ps
handlerParamToInputFieldRefs :: HandlerParam -> [InputFieldRef]
handlerParamToInputFieldRefs (Update _ fr io) = [fr] ++ [ fr' | (_,fr',_) <- fromMaybe [] io]
handlerParamToInputFieldRefs (Insert _ (Just (_, io)) _) = [ fr | (_,fr,_) <- io ]
handlerParamToInputFieldRefs (Insert _ _ _) = []
handlerParamToInputFieldRefs (GetById _ ifr _) = [ifr]
handlerParamToInputFieldRefs (Call _ ifrs) = ifrs
handlerParamToInputFieldRefs _ = []
updateHandlerMaybeCurrentTime :: [HandlerParam] -> String
updateHandlerMaybeCurrentTime ps = if InputFieldNow `elem` inputFields
then (T.unpack $(codegenFile "codegen/prepare-now.cg"))
else ""
where inputFields = concatMap handlerParamToInputFieldRefs ps
updateHandlerMaybeAuth :: [HandlerParam] -> String
updateHandlerMaybeAuth ps
| (not . null) (filter isAuthField inputFields) = T.unpack $(codegenFile "codegen/load-auth.cg")
| otherwise = ""
where inputFields = concatMap handlerParamToInputFieldRefs ps
isAuthField (InputFieldAuth _) = True
isAuthField _ = False
updateHandlerReturnRunDB :: [HandlerParam] -> String
updateHandlerReturnRunDB ps = case listToMaybe $ filter isReturn ps of
Just (Return ofrs) -> T.unpack $(codegenFile "codegen/rundb-return-fields.cg")
_ -> T.unpack $(codegenFile "codegen/rundb-return-none.cg")
where
isReturn (Return _) = True
isReturn _ = False
trOutputField (pn,OutputFieldLocalParam vn) = rstrip $ T.unpack $(codegenFile "codegen/output-field-local-param.cg")
updateHandler :: State Context String
updateHandler = do
ps <- gets ctxHandlerParams
liftM concat $ sequence ([
updateHandlerReadJsonFields,
return $ updateHandlerMaybeCurrentTime ps,
return $ updateHandlerMaybeAuth ps,
requireStmts,
return $ (T.unpack $(codegenFile "codegen/rundb.cg")),
liftM concat $ mapM updateHandlerRunDB $ zip [1..] ps,
return $ updateHandlerReturnRunDB ps,
return $ T.unpack $(codegenFile "codegen/update-handler-footer.cg")
] :: [State Context String])