module Moo.Core where
import Control.Applicative ((<$>), (<*>))
import Control.Monad.Reader (ReaderT)
import qualified Data.Configurator as C
import Data.Configurator.Types (Config)
import qualified Data.Text as T
import Database.HDBC.PostgreSQL (connectPostgreSQL)
import Database.HDBC.Sqlite3 (connectSqlite3)
import System.Environment (getEnvironment)
import Database.Schema.Migrations ()
import Database.Schema.Migrations.Store (MigrationStore, StoreData)
import Database.Schema.Migrations.Backend
import Database.Schema.Migrations.Backend.HDBC
type AppT a = ReaderT AppState IO a
type CommandHandler = StoreData -> AppT ()
data AppState = AppState { _appOptions :: CommandOptions
, _appCommand :: Command
, _appRequiredArgs :: [String]
, _appOptionalArgs :: [String]
, _appStore :: MigrationStore
, _appDatabaseConnStr :: DbConnDescriptor
, _appDatabaseType :: String
, _appStoreData :: StoreData
}
type ShellEnvironment = [(String, String)]
data Configuration = Configuration
{ _connectionString :: String
, _databaseType :: String
, _migrationStorePath :: FilePath
}
loadConfiguration :: Maybe FilePath -> IO (Either String Configuration)
loadConfiguration pth = do
mCfg <- case pth of
Nothing -> fromShellEnvironment <$> getEnvironment
Just path -> fromConfigurator =<< C.load [C.Required path]
case mCfg of
Nothing -> do
case pth of
Nothing -> return $ Left "Missing required environment variables"
Just path -> return $ Left $ "Could not load configuration from " ++ path
Just cfg -> return $ Right cfg
fromShellEnvironment :: ShellEnvironment -> Maybe Configuration
fromShellEnvironment env = Configuration <$> connectionString
<*> databaseType
<*> migrationStorePath
where
connectionString = envLookup envDatabaseName
databaseType = envLookup envDatabaseType
migrationStorePath = envLookup envStoreName
envLookup = (\evar -> lookup evar env)
fromConfigurator :: Config -> IO (Maybe Configuration)
fromConfigurator conf = do
let configLookup = C.lookup conf . T.pack
connectionString <- configLookup envDatabaseName
databaseType <- configLookup envDatabaseType
migrationStorePath <- configLookup envStoreName
return $ Configuration <$> connectionString
<*> databaseType
<*> migrationStorePath
data CommandOptions = CommandOptions { _configFilePath :: Maybe String
, _test :: Bool
, _noAsk :: Bool
}
data Command = Command { _cName :: String
, _cRequired :: [String]
, _cOptional :: [String]
, _cAllowedOptions :: [String]
, _cDescription :: String
, _cHandler :: CommandHandler
}
data ConfigData = ConfigData { _dbTypeStr :: String
, _dbConnStr :: String
, _fileStorePath :: String
}
newtype DbConnDescriptor = DbConnDescriptor String
databaseTypes :: [(String, String -> IO Backend)]
databaseTypes = [ ("postgresql", fmap hdbcBackend . connectPostgreSQL)
, ("sqlite3", fmap hdbcBackend . connectSqlite3)
]
envDatabaseType :: String
envDatabaseType = "DBM_DATABASE_TYPE"
envDatabaseName :: String
envDatabaseName = "DBM_DATABASE"
envStoreName :: String
envStoreName = "DBM_MIGRATION_STORE"