jtdaugherty/dbmigrations

Configuration file feature

ExternalReality opened this issue · 4 comments

As a user I would like to be able to specify whether the database type, store path and database connection string get read from a configuration file or from the environment.

Implementing this brings up a few behavioral issues:

  1. What should Moo read by default, the environment or the config file?
    • Configuration file by default with option to specify something like --config-file=[path] or --env (for environment)
    • Environment default; --config-file=[path] optional argument
  2. What command line options specify the desired behavior?
  3. If the user chooses to read from a config file and does not specify a path where does Moo look?
  4. What configuration format(s) are acceptable? (?? YAML ??)
DBM_DATABASE_TYPE:     "postgresql" 
DBM_DATABASE:          "a=beautiful; connection=string"
DBM_MIGRATION_STORE:   "Path to a migration store"

A simple implementation using Data.Yaml in the applicative. (Data.Yaml is based on Aeson and the names haven't changed yet.)

module Moo.ConfigParser where

import Data.Yaml
import Moo.Core


parseConfigOptions :: FilePath -> IO ConfigData
parseConfigOptions configFilePath = do
  configContents <- decodeFile configFilePath

  case configContents of
    Nothing  -> error "Failed Parsing Yaml"
    Just a   -> return a
module Moo.Core where

import Control.Applicative ( (<$>), (<*>) )
import Data.Yaml ( FromJSON( parseJSON ), Value ( Object ), (.:) )

...

-- |ConfigOptions are those options read from configuration file
--  or environment. 
data ConfigData = ConfigData { _dbTypeStr     :: String  
                             , _dbConnStr     :: String 
                             , _fileStorePath :: String
                             }


instance FromJSON ConfigData where
   parseJSON (Object v) = ConfigData                 <$>     
                          v .: "DBM_DATABASE_TYPE"   <*>   
                          v .: "DBM_DATABASE"        <*>
                          v .: "DBM_MIGRATION_STORE" 

   parseJSON _           = mzero
module Moo.CommandInterface

...

commandOptions :: [ OptDescr (CommandOptions -> IO CommandOptions) ]
commandOptions =  [ optionConfigFile
                  , optionTest
                  , optionNoAsk
                  ]


optionConfigFile :: OptDescr (CommandOptions -> IO CommandOptions)
optionConfigFile = Option "c" ["config-file"]
                   (ReqArg (\arg opt ->
                             return opt { _configFilePath = Just arg }) "FILE")
                   "Specify location of configuration file"

The rest would depend on the answers to the questions above I suppose.

On the default behavior, I'd say look at the environment unless --config is specified. If --config is given and the config file doesn't exist or can't be read for any reason, that should constitute an error; otherwise, transparent fallback to the environment could be very, very confusing. As for the format, I think YAML would be the least jarring change as it is already the format used by the migration files. I'd be open to other format options (such as ini-style files as supported by the hsini package), but at the moment I don't see how that could provide enough extra benefit to justify using two different formats.

Given your recent pull request, it looks like we can close this. Is there anything else that needs doing on this?

Yes, this issue can be closed.

Great! Thanks for contributing the feature! :)