module YesodDsl.Simplify (simplify) where import YesodDsl.AST import Data.Generics import Data.Either import Data.Generics.Uniplate.Data import qualified Data.List as L import Data.Maybe import qualified Data.Map as Map simplify :: Module -> Module simplify m = everywhere ((mkT sHandler) . (mkT sExpr) . (mkT sStmt) . (mkT mapEntityRef)) m where sExpr (SubQueryExpr sq) = SubQueryExpr $ mapSq sq sExpr (ExistsExpr sq) = ExistsExpr $ mapSq sq sExpr x = x sStmt (Require sq) = Require $ mapSq sq sStmt (IfFilter (pn,js,be,ob,uf)) = IfFilter (pn, map mapJoin js, be, ob, uf) sStmt (Select sq) = Select $ mapSq sq sStmt x = x mapSq sq = let sq' = sq { sqJoins = map mapJoin $ sqJoins sq } in sq' { sqFields = concatMap (expand sq') $ sqFields sq', sqWhere = everywhere (mkT sExpr) $ sqWhere sq' } mapJoin j = j { joinEntity = mapEntityRef $ joinEntity j, joinExpr = joinExpr j >>= Just . (everywhere $ (mkT sExpr)) } lookupEntity en = L.find ((==en) . entityName) $ modEntities m mapEntityRef l@(Left en) = fromMaybe l $ lookupEntity en >>= Just . Right mapEntityRef x = x expand sq (SelectField vr@(Var vn _ _) fn Nothing) = fromMaybe [] $ do (e,_) <- Map.lookup vn $ sqAliases sq Just $ [ SelectField vr fn (Just $ fieldJsonName f) | f <- entityFields e, fieldName f == fn ] expand sq (SelectAllFields (Var vn _ _)) = fromMaybe [] $ do (e,_) <- Map.lookup vn $ sqAliases sq Just $ [ SelectField (Var vn (Left "") False) (fieldName f) (Just $ fieldJsonName f) | f <- entityFields e, fieldInternal f == False ] expand _ x = [x] sHandler :: Handler -> Handler sHandler h = everywhere ((mkT mapVarRef) . (mkT mapStmt) . (mkT mapSq)) h where baseAliases = Map.unions [ sqAliases sq | Select sq <- universeBi h ] mapStmt df@(DeleteFrom er vn _) = everywhere (mkT $ mapSqVarRef $ Map.unions [ baseAliases, Map.fromList $ rights [ er >>= \e -> Right (vn, (e, False)) ] ]) df mapStmt i@(IfFilter (_,js,_,_,_)) = everywhere (mkT $ mapSqVarRef $ Map.unions [ baseAliases, Map.fromList $ rights [ joinEntity j >>= \e -> Right (joinAlias j,(e, isOuterJoin $ joinType j)) | j <- js ] ]) i mapStmt i = i mapSq sq = everywhere (mkT $ mapSqVarRef $ sqAliases sq) sq mapSqVarRef aliases (Var vn (Left "") _) = case Map.lookup vn aliases of Just (e,mf) -> Var vn (Right e) mf _ -> Var vn (lookupEntityRef vn) False mapSqVarRef _ v = v lookupEntityRef vn = case listToMaybe [ er | GetById er _ vn' <- universeBi h, vn' == vn ] of Just er -> er Nothing -> Left "" mapVarRef (Var vn (Left "") _) = Var vn (lookupEntityRef vn) False mapVarRef v = v