{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} module Moo.CommandHandlers where import Moo.Core import Moo.CommandUtils import Control.Monad ( when, forM_ ) import Data.Maybe ( isJust ) import Control.Monad.Reader ( asks ) import System.Exit ( exitWith, ExitCode(..), exitSuccess ) import Control.Monad.Trans ( liftIO ) import Database.HDBC ( IConnection(commit, rollback)) import Database.Schema.Migrations.Store hiding (getMigrations) import Database.Schema.Migrations import Database.Schema.Migrations.Backend newCommand :: CommandHandler newCommand storeData = do required <- asks _appRequiredArgs store <- asks _appStore let [migrationId] = required noAsk <- fmap _noAsk $ asks _appOptions liftIO $ do fullPath <- fullMigrationName store migrationId when (isJust $ storeLookup storeData migrationId) $ do putStrLn $ "Migration " ++ (show fullPath) ++ " already exists" exitWith (ExitFailure 1) -- Default behavior: ask for dependencies deps <- if noAsk then (return []) else do putStrLn $ "Selecting dependencies for new \ \migration: " ++ migrationId interactiveAskDeps storeData result <- if noAsk then (return True) else (confirmCreation migrationId deps) case result of True -> do status <- createNewMigration store migrationId deps case status of Left e -> putStrLn e >> (exitWith (ExitFailure 1)) Right _ -> putStrLn $ "Migration created successfully: " ++ show fullPath False -> do putStrLn "Migration creation cancelled." upgradeCommand :: CommandHandler upgradeCommand storeData = do isTesting <- fmap _test $ asks _appOptions withConnection $ \(AnyIConnection conn) -> do ensureBootstrappedBackend conn >> commit conn migrationNames <- missingMigrations conn storeData when (null migrationNames) $ do putStrLn "Database is up to date." exitSuccess forM_ migrationNames $ \migrationName -> do m <- lookupMigration storeData migrationName apply m storeData conn False case isTesting of True -> do rollback conn putStrLn "Upgrade test successful." False -> do commit conn putStrLn "Database successfully upgraded." upgradeListCommand :: CommandHandler upgradeListCommand storeData = do withConnection $ \(AnyIConnection conn) -> do ensureBootstrappedBackend conn >> commit conn migrationNames <- missingMigrations conn storeData when (null migrationNames) $ do putStrLn "Database is up to date." exitSuccess putStrLn "Migrations to install:" forM_ migrationNames (putStrLn . (" " ++)) reinstallCommand :: CommandHandler reinstallCommand storeData = do isTesting <- fmap _test $ asks _appOptions required <- asks _appRequiredArgs let [migrationId] = required withConnection $ \(AnyIConnection conn) -> do ensureBootstrappedBackend conn >> commit conn m <- lookupMigration storeData migrationId revert m storeData conn apply m storeData conn True case isTesting of False -> do commit conn putStrLn "Migration successfully reinstalled." True -> do rollback conn putStrLn "Reinstall test successful." listCommand :: CommandHandler listCommand _ = do withConnection $ \(AnyIConnection conn) -> do ensureBootstrappedBackend conn >> commit conn ms <- getMigrations conn forM_ ms $ \m -> when (not $ m == rootMigrationName) $ putStrLn m applyCommand :: CommandHandler applyCommand storeData = do isTesting <- fmap _test $ asks _appOptions required <- asks _appRequiredArgs let [migrationId] = required withConnection $ \(AnyIConnection conn) -> do ensureBootstrappedBackend conn >> commit conn m <- lookupMigration storeData migrationId apply m storeData conn True case isTesting of False -> do commit conn putStrLn "Successfully applied migrations." True -> do rollback conn putStrLn "Migration installation test successful." revertCommand :: CommandHandler revertCommand storeData = do isTesting <- fmap _test $ asks _appOptions required <- asks _appRequiredArgs let [migrationId] = required withConnection $ \(AnyIConnection conn) -> do ensureBootstrappedBackend conn >> commit conn m <- lookupMigration storeData migrationId revert m storeData conn case isTesting of False -> do commit conn putStrLn "Successfully reverted migrations." True -> do rollback conn putStrLn "Migration uninstallation test successful." testCommand :: CommandHandler testCommand storeData = do required <- asks _appRequiredArgs let [migrationId] = required withConnection $ \(AnyIConnection conn) -> do ensureBootstrappedBackend conn >> commit conn m <- lookupMigration storeData migrationId migrationNames <- missingMigrations conn storeData -- If the migration is already installed, remove it as part of -- the test when (not $ migrationId `elem` migrationNames) $ do revert m storeData conn return () applied <- apply m storeData conn True forM_ (reverse applied) $ \migration -> do revert migration storeData conn rollback conn putStrLn "Successfully tested migrations."