packages feed

dbmigrations 2.0.0 → 2.1.0

raw patch · 26 files changed

+294/−223 lines, 26 filesdep +aesondep +string-conversionsdep +unordered-containersdep −yaml-lightPVP ok

version bump matches the API change (PVP)

Dependencies added: aeson, string-conversions, unordered-containers, yaml

Dependencies removed: yaml-light

API changes (from Hackage documentation)

- Database.Schema.Migrations.Filesystem: instance GHC.Exception.Exception Database.Schema.Migrations.Filesystem.FilesystemStoreError
+ Database.Schema.Migrations.CycleDetection: hasCycle :: Graph g => g a b -> Bool
+ Database.Schema.Migrations.Filesystem: instance GHC.Exception.Type.Exception Database.Schema.Migrations.Filesystem.FilesystemStoreError
+ Database.Schema.Migrations.Filesystem.Serialize: serializeMigration :: Migration -> ByteString
- Database.Schema.Migrations: missingMigrations :: Backend -> StoreData -> IO [String]
+ Database.Schema.Migrations: missingMigrations :: Backend -> StoreData -> IO [Text]
- Database.Schema.Migrations.Backend: Backend :: IO Migration -> IO Bool -> (Migration -> IO ()) -> (Migration -> IO ()) -> IO [String] -> IO () -> IO () -> IO () -> Backend
+ Database.Schema.Migrations.Backend: Backend :: IO Migration -> IO Bool -> (Migration -> IO ()) -> (Migration -> IO ()) -> IO [Text] -> IO () -> IO () -> IO () -> Backend
- Database.Schema.Migrations.Backend: [getMigrations] :: Backend -> IO [String]
+ Database.Schema.Migrations.Backend: [getMigrations] :: Backend -> IO [Text]
- Database.Schema.Migrations.Backend: rootMigrationName :: String
+ Database.Schema.Migrations.Backend: rootMigrationName :: Text
- Database.Schema.Migrations.Backend.HDBC: hdbcBackend :: (IConnection conn) => conn -> Backend
+ Database.Schema.Migrations.Backend.HDBC: hdbcBackend :: IConnection conn => conn -> Backend
- Database.Schema.Migrations.Dependencies: DG :: [(a, Int)] -> [(String, Int)] -> Gr String String -> DependencyGraph a
+ Database.Schema.Migrations.Dependencies: DG :: [(a, Int)] -> [(Text, Int)] -> Gr Text Text -> DependencyGraph a
- Database.Schema.Migrations.Dependencies: [depGraphNameMap] :: DependencyGraph a -> [(String, Int)]
+ Database.Schema.Migrations.Dependencies: [depGraphNameMap] :: DependencyGraph a -> [(Text, Int)]
- Database.Schema.Migrations.Dependencies: [depGraph] :: DependencyGraph a -> Gr String String
+ Database.Schema.Migrations.Dependencies: [depGraph] :: DependencyGraph a -> Gr Text Text
- Database.Schema.Migrations.Dependencies: depId :: Dependable a => a -> String
+ Database.Schema.Migrations.Dependencies: depId :: Dependable a => a -> Text
- Database.Schema.Migrations.Dependencies: dependencies :: (Dependable d) => DependencyGraph d -> String -> [String]
+ Database.Schema.Migrations.Dependencies: dependencies :: Dependable d => DependencyGraph d -> Text -> [Text]
- Database.Schema.Migrations.Dependencies: depsOf :: Dependable a => a -> [String]
+ Database.Schema.Migrations.Dependencies: depsOf :: Dependable a => a -> [Text]
- Database.Schema.Migrations.Dependencies: mkDepGraph :: (Dependable a) => [a] -> Either String (DependencyGraph a)
+ Database.Schema.Migrations.Dependencies: mkDepGraph :: Dependable a => [a] -> Either String (DependencyGraph a)
- Database.Schema.Migrations.Dependencies: reverseDependencies :: (Dependable d) => DependencyGraph d -> String -> [String]
+ Database.Schema.Migrations.Dependencies: reverseDependencies :: Dependable d => DependencyGraph d -> Text -> [Text]
- Database.Schema.Migrations.Filesystem: migrationFromFile :: FilesystemStoreSettings -> String -> IO (Either String Migration)
+ Database.Schema.Migrations.Filesystem: migrationFromFile :: FilesystemStoreSettings -> Text -> IO (Either String Migration)
- Database.Schema.Migrations.Migration: Migration :: Maybe UTCTime -> String -> Maybe String -> String -> Maybe String -> [String] -> Migration
+ Database.Schema.Migrations.Migration: Migration :: Maybe UTCTime -> Text -> Maybe Text -> Text -> Maybe Text -> [Text] -> Migration
- Database.Schema.Migrations.Migration: [mApply] :: Migration -> String
+ Database.Schema.Migrations.Migration: [mApply] :: Migration -> Text
- Database.Schema.Migrations.Migration: [mDeps] :: Migration -> [String]
+ Database.Schema.Migrations.Migration: [mDeps] :: Migration -> [Text]
- Database.Schema.Migrations.Migration: [mDesc] :: Migration -> Maybe String
+ Database.Schema.Migrations.Migration: [mDesc] :: Migration -> Maybe Text
- Database.Schema.Migrations.Migration: [mId] :: Migration -> String
+ Database.Schema.Migrations.Migration: [mId] :: Migration -> Text
- Database.Schema.Migrations.Migration: [mRevert] :: Migration -> Maybe String
+ Database.Schema.Migrations.Migration: [mRevert] :: Migration -> Maybe Text
- Database.Schema.Migrations.Migration: emptyMigration :: String -> Migration
+ Database.Schema.Migrations.Migration: emptyMigration :: Text -> Migration
- Database.Schema.Migrations.Migration: newMigration :: String -> Migration
+ Database.Schema.Migrations.Migration: newMigration :: Text -> Migration
- Database.Schema.Migrations.Store: DependencyReferenceError :: String -> String -> MapValidationError
+ Database.Schema.Migrations.Store: DependencyReferenceError :: Text -> Text -> MapValidationError
- Database.Schema.Migrations.Store: MigrationStore :: (String -> IO (Either String Migration)) -> (Migration -> IO ()) -> IO [String] -> (String -> IO String) -> MigrationStore
+ Database.Schema.Migrations.Store: MigrationStore :: (Text -> IO (Either String Migration)) -> (Migration -> IO ()) -> IO [Text] -> (Text -> IO FilePath) -> MigrationStore
- Database.Schema.Migrations.Store: [fullMigrationName] :: MigrationStore -> String -> IO String
+ Database.Schema.Migrations.Store: [fullMigrationName] :: MigrationStore -> Text -> IO FilePath
- Database.Schema.Migrations.Store: [getMigrations] :: MigrationStore -> IO [String]
+ Database.Schema.Migrations.Store: [getMigrations] :: MigrationStore -> IO [Text]
- Database.Schema.Migrations.Store: [loadMigration] :: MigrationStore -> String -> IO (Either String Migration)
+ Database.Schema.Migrations.Store: [loadMigration] :: MigrationStore -> Text -> IO (Either String Migration)
- Database.Schema.Migrations.Store: leafMigrations :: StoreData -> [String]
+ Database.Schema.Migrations.Store: leafMigrations :: StoreData -> [Text]
- Database.Schema.Migrations.Store: storeLookup :: StoreData -> String -> Maybe Migration
+ Database.Schema.Migrations.Store: storeLookup :: StoreData -> Text -> Maybe Migration
- Database.Schema.Migrations.Store: type MigrationMap = Map String Migration
+ Database.Schema.Migrations.Store: type MigrationMap = Map Text Migration
- Database.Schema.Migrations.Test.BackendTest: catchAll :: BackendConnection c => c -> (IO a -> IO a -> IO a)
+ Database.Schema.Migrations.Test.BackendTest: catchAll :: BackendConnection c => c -> IO a -> IO a -> IO a
- Database.Schema.Migrations.Test.BackendTest: getTables :: BackendConnection c => c -> IO [String]
+ Database.Schema.Migrations.Test.BackendTest: getTables :: BackendConnection c => c -> IO [ByteString]
- Moo.CommandUtils: confirmCreation :: String -> [String] -> IO Bool
+ Moo.CommandUtils: confirmCreation :: Text -> [Text] -> IO Bool
- Moo.CommandUtils: getCurrentTimestamp :: IO String
+ Moo.CommandUtils: getCurrentTimestamp :: IO Text
- Moo.CommandUtils: interactiveAskDeps :: StoreData -> IO [String]
+ Moo.CommandUtils: interactiveAskDeps :: StoreData -> IO [Text]
- Moo.CommandUtils: lookupMigration :: StoreData -> String -> IO Migration
+ Moo.CommandUtils: lookupMigration :: StoreData -> Text -> IO Migration
- Moo.Core: AppState :: CommandOptions -> Command -> [String] -> [String] -> Backend -> MigrationStore -> StoreData -> Bool -> Bool -> AppState
+ Moo.Core: AppState :: CommandOptions -> Command -> [Text] -> [Text] -> Backend -> MigrationStore -> StoreData -> Bool -> Bool -> AppState
- Moo.Core: [_appOptionalArgs] :: AppState -> [String]
+ Moo.Core: [_appOptionalArgs] :: AppState -> [Text]
- Moo.Core: [_appRequiredArgs] :: AppState -> [String]
+ Moo.Core: [_appRequiredArgs] :: AppState -> [Text]

Files

MOO.TXT view
@@ -74,10 +74,12 @@     Confirm: create migration 'hello-world'       (No dependencies)     Are you sure? (yn): y-    Migration created successfully: ".../hello-world.txt"+    Migration created successfully: ".../hello-world.yml" +   New migration will be stored with .yml extension. Older .txt migrations are supported.+  6. Edit the migration you created. In this case, moo created a file-    $DBM_MIGRATION_STORE/hello_world.txt that looks like this:+    $DBM_MIGRATION_STORE/hello_world.yml that looks like this:        Description: (Description here.)       Created: 2015-02-18 00:50:12.041176 UTC
dbmigrations.cabal view
@@ -1,5 +1,5 @@ Name:                dbmigrations-Version:             2.0.0+Version:             2.1.0 Synopsis:            An implementation of relational database "migrations" Description:         A library and program for the creation,                      management, and installation of schema updates@@ -79,20 +79,25 @@     directory >= 1.0,     fgl >= 5.4,     template-haskell,-    yaml-light >= 0.1,+    yaml,     bytestring >= 0.9,+    string-conversions >= 0.4,     text >= 0.11,     configurator >= 0.2,     split >= 0.2.2,-    HUnit >= 1.2+    HUnit >= 1.2,+    aeson < 2,+    unordered-containers    Hs-Source-Dirs:    src   Exposed-Modules:           Database.Schema.Migrations           Database.Schema.Migrations.Backend           Database.Schema.Migrations.Backend.HDBC+          Database.Schema.Migrations.CycleDetection           Database.Schema.Migrations.Dependencies           Database.Schema.Migrations.Filesystem+          Database.Schema.Migrations.Filesystem.Serialize           Database.Schema.Migrations.Migration           Database.Schema.Migrations.Store           Database.Schema.Migrations.Test.BackendTest@@ -102,10 +107,6 @@           Moo.Core           Moo.Main -  Other-Modules:-          Database.Schema.Migrations.CycleDetection-          Database.Schema.Migrations.Filesystem.Serialize- test-suite dbmigrations-tests   default-language: Haskell2010   type: exitcode-stdio-1.0@@ -119,8 +120,9 @@     directory >= 1.0,     fgl >= 5.4,     template-haskell,-    yaml-light >= 0.1,+    yaml,     bytestring >= 0.9,+    string-conversions >= 0.4,     MissingH,     HDBC >= 2.2.1,     HUnit >= 1.2,@@ -139,7 +141,6 @@     FilesystemTest     MigrationsTest     StoreTest-    TestDriver     InMemoryStore     LinearMigrationsTest     ConfigurationTest@@ -150,8 +151,8 @@   else     ghc-options: -threaded -Wall -fwarn-tabs -funbox-strict-fields -  Hs-Source-Dirs:  src,test-  Main-is:         TestDriver.hs+  Hs-Source-Dirs:  test+  Main-is:         Main.hs  Executable moo   default-language: Haskell2010
src/Database/Schema/Migrations.hs view
@@ -9,6 +9,7 @@     ) where +import Data.Text ( Text ) import qualified Data.Set as Set import Data.Maybe ( catMaybes ) @@ -25,7 +26,7 @@ -- |Given a 'B.Backend' and a 'S.MigrationMap', query the backend and -- return a list of migration names which are available in the -- 'S.MigrationMap' but which are not installed in the 'B.Backend'.-missingMigrations :: B.Backend -> S.StoreData -> IO [String]+missingMigrations :: B.Backend -> S.StoreData -> IO [Text] missingMigrations backend storeData = do   let storeMigrationNames = map mId $ S.storeMigrations storeData   backendMigrations <- B.getMigrations backend
src/Database/Schema/Migrations/Backend.hs view
@@ -1,16 +1,19 @@+{-# LANGUAGE OverloadedStrings #-} module Database.Schema.Migrations.Backend     ( Backend(..)     , rootMigrationName     ) where +import Data.Text ( Text )+ import Database.Schema.Migrations.Migration     ( Migration(..) )  -- |Backend instances should use this as the name of the migration -- returned by getBootstrapMigration; this migration is special -- because it cannot be reverted.-rootMigrationName :: String+rootMigrationName :: Text rootMigrationName = "root"  -- |A Backend represents a database engine backend such as MySQL or@@ -55,7 +58,7 @@             -- does not supply a revert instruction, this has no effect             -- other than bookkeeping. -            , getMigrations :: IO [String]+            , getMigrations :: IO [Text]             -- ^ Returns a list of installed migration names from the             -- backend. @@ -71,4 +74,4 @@             }  instance Show Backend where-   show _ = show "dbmigrations backend"+   show _ = "dbmigrations backend"
src/Database/Schema/Migrations/Backend/HDBC.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module Database.Schema.Migrations.Backend.HDBC     ( hdbcBackend     )@@ -22,22 +23,25 @@     , newMigration     ) +import Data.Text ( Text )+import Data.String.Conversions ( cs, (<>) )+ import Control.Applicative ( (<$>) ) import Data.Time.Clock (getCurrentTime) -migrationTableName :: String+migrationTableName :: Text migrationTableName = "installed_migrations" -createSql :: String-createSql = "CREATE TABLE " ++ migrationTableName ++ " (migration_id TEXT)"+createSql :: Text+createSql = "CREATE TABLE " <> migrationTableName <> " (migration_id TEXT)" -revertSql :: String-revertSql = "DROP TABLE " ++ migrationTableName+revertSql :: Text+revertSql = "DROP TABLE " <> migrationTableName  -- |General Backend constructor for all HDBC connection implementations. hdbcBackend :: (IConnection conn) => conn -> Backend hdbcBackend conn =-    Backend { isBootstrapped = elem migrationTableName <$> getTables conn+    Backend { isBootstrapped = elem (cs migrationTableName) <$> getTables conn             , getBootstrapMigration =                   do                     ts <- getCurrentTime@@ -49,22 +53,22 @@                         }              , applyMigration = \m -> do-                runRaw conn (mApply m)-                run conn ("INSERT INTO " ++ migrationTableName +++                runRaw conn (cs $ mApply m)+                _ <- run conn (cs $ "INSERT INTO " <> migrationTableName <>                           " (migration_id) VALUES (?)") [toSql $ mId m]                 return ()              , revertMigration = \m -> do                   case mRevert m of                     Nothing -> return ()-                    Just query -> runRaw conn query+                    Just query -> runRaw conn (cs query)                   -- Remove migration from installed_migrations in either case.-                  run conn ("DELETE FROM " ++ migrationTableName +++                  _ <- run conn (cs $ "DELETE FROM " <> migrationTableName <>                             " WHERE migration_id = ?") [toSql $ mId m]                   return ()              , getMigrations = do-                results <- quickQuery' conn ("SELECT migration_id FROM " ++ migrationTableName) []+                results <- quickQuery' conn (cs $ "SELECT migration_id FROM " <> migrationTableName) []                 return $ map (fromSql . head) results              , commitBackend = commit conn
src/Database/Schema/Migrations/Dependencies.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TypeSynonymInstances, OverloadedStrings #-} -- |This module types and functions for representing a dependency -- graph of arbitrary objects and functions for querying such graphs -- to get dependency and reverse dependency information.@@ -11,7 +11,9 @@     ) where +import Data.Text ( Text ) import Data.Maybe ( fromJust )+import Data.Monoid ( (<>) ) import Data.Graph.Inductive.Graph ( Graph(..), nodes, edges, Node, suc, pre, lab ) import Data.Graph.Inductive.PatriciaTree ( Gr ) @@ -21,9 +23,9 @@ -- and a list of other objects upon which they depend. class (Eq a, Ord a) => Dependable a where     -- |The identifiers of the objects on which @a@ depends.-    depsOf :: a -> [String]+    depsOf :: a -> [Text]     -- |The identifier of a 'Dependable' object.-    depId :: a -> String+    depId :: a -> Text  -- |A 'DependencyGraph' represents a collection of objects together -- with a graph of their dependency relationships.  This is intended@@ -31,14 +33,14 @@ data DependencyGraph a = DG { depGraphObjectMap :: [(a, Int)]                             -- ^ A mapping of 'Dependable' objects to                             -- their graph vertex indices.-                            , depGraphNameMap :: [(String, Int)]+                            , depGraphNameMap :: [(Text, Int)]                             -- ^ A mapping of 'Dependable' object                             -- identifiers to their graph vertex                             -- indices.-                            , depGraph :: Gr String String+                            , depGraph :: Gr Text Text                             -- ^ A directed 'Gr' (graph) of the                             -- 'Dependable' objects' dependency-                            -- relationships, with 'String' vertex and+                            -- relationships, with 'Text' vertex and                             -- edge labels.                             } @@ -65,14 +67,14 @@       n = [ (fromJust $ lookup o ids, depId o) | o <- objects ]       e = [ ( fromJust $ lookup o ids             , fromJust $ lookup d ids-            , depId o ++ " -> " ++ depId d) | o <- objects, d <- depsOf' o ]+            , depId o <> " -> " <> depId d) | o <- objects, d <- depsOf' o ]       depsOf' o = map (\i -> fromJust $ lookup i objMap) $ depsOf o        objMap = map (\o -> (depId o, o)) objects       ids = zip objects [1..]       names = map (\(o,i) -> (depId o, i)) ids -type NextNodesFunc = Gr String String -> Node -> [Node]+type NextNodesFunc = Gr Text Text -> Node -> [Node]  cleanLDups :: (Eq a) => [a] -> [a] cleanLDups [] = []@@ -82,16 +84,16 @@ -- |Given a dependency graph and an ID, return the IDs of objects that -- the object depends on.  IDs are returned with least direct -- dependencies first (i.e., the apply order).-dependencies :: (Dependable d) => DependencyGraph d -> String -> [String]+dependencies :: (Dependable d) => DependencyGraph d -> Text -> [Text] dependencies g m = reverse $ cleanLDups $ dependenciesWith suc g m  -- |Given a dependency graph and an ID, return the IDs of objects that -- depend on it.  IDs are returned with least direct reverse -- dependencies first (i.e., the revert order).-reverseDependencies :: (Dependable d) => DependencyGraph d -> String -> [String]+reverseDependencies :: (Dependable d) => DependencyGraph d -> Text -> [Text] reverseDependencies g m = reverse $ cleanLDups $ dependenciesWith pre g m -dependenciesWith :: (Dependable d) => NextNodesFunc -> DependencyGraph d -> String -> [String]+dependenciesWith :: (Dependable d) => NextNodesFunc -> DependencyGraph d -> Text -> [Text] dependenciesWith nextNodes dg@(DG _ nMap theGraph) name =     let lookupId = fromJust $ lookup name nMap         depNodes = nextNodes theGraph lookupId
src/Database/Schema/Migrations/Filesystem.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables #-}+{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables, OverloadedStrings #-} -- |This module provides a type for interacting with a -- filesystem-backed 'MigrationStore'. module Database.Schema.Migrations.Filesystem@@ -9,12 +9,14 @@     ) where -import Prelude hiding ( catch )+import Prelude  import System.Directory ( getDirectoryContents, doesFileExist )-import System.FilePath ( (</>), takeExtension, dropExtension-                       , takeFileName, takeBaseName )-import Data.ByteString.Char8 ( unpack )+import System.FilePath ( (</>), takeExtension, dropExtension, takeBaseName )+import Data.Text ( Text )+import qualified Data.Text as T+import qualified Data.ByteString.Char8 as BSC+import Data.String.Conversions ( cs, (<>) )  import Data.Typeable ( Typeable ) import Data.Time.Clock ( UTCTime )@@ -23,9 +25,11 @@  import Control.Applicative ( (<$>) ) import Control.Monad ( filterM )-import Control.Exception ( IOException, Exception(..), throw, catch )+import Control.Exception ( Exception(..), throw, catch ) -import Data.Yaml.YamlLight+import Data.Aeson as J (Object, Value(String, Null))+import Data.HashMap.Strict as M (toList)+import Data.Yaml  import Database.Schema.Migrations.Migration     ( Migration(..)@@ -34,7 +38,7 @@ import Database.Schema.Migrations.Filesystem.Serialize import Database.Schema.Migrations.Store -type FieldProcessor = String -> Migration -> Maybe Migration+type FieldProcessor = Text -> Migration -> Maybe Migration  data FilesystemStoreSettings = FSStore { storePath :: FilePath } @@ -47,11 +51,14 @@ throwFS = throw . FilesystemStoreError  filenameExtension :: String-filenameExtension = ".txt"+filenameExtension = ".yml" +filenameExtensionTxt :: String+filenameExtensionTxt = ".txt"+ filesystemStore :: FilesystemStoreSettings -> MigrationStore filesystemStore s =-    MigrationStore { fullMigrationName = fsFullMigrationName s+    MigrationStore { fullMigrationName = fmap addNewMigrationExtension . fsFullMigrationName s                     , loadMigration = \theId -> migrationFromFile s theId @@ -60,37 +67,50 @@                        let migrationFilenames = [ f | f <- contents, isMigrationFilename f ]                            fullPaths = [ (f, storePath s </> f) | f <- migrationFilenames ]                        existing <- filterM (\(_, full) -> doesFileExist full) fullPaths-                       return [ dropExtension short | (short, _) <- existing ]+                       return [ cs $ dropExtension short | (short, _) <- existing ]                     , saveMigration = \m -> do                        filename <- fsFullMigrationName s $ mId m-                       writeFile filename $ serializeMigration m+                       BSC.writeFile (cs $ addNewMigrationExtension filename) $ serializeMigration m                    } -fsFullMigrationName :: FilesystemStoreSettings -> FilePath -> IO FilePath-fsFullMigrationName s name = return $ storePath s </> name ++ filenameExtension+addNewMigrationExtension :: FilePath -> FilePath+addNewMigrationExtension path = path <> filenameExtension -isMigrationFilename :: FilePath -> Bool-isMigrationFilename path = takeExtension path == filenameExtension+addMigrationExtension :: FilePath -> String -> FilePath+addMigrationExtension path ext = path <> ext +-- |Build path to migrations without extension.+fsFullMigrationName :: FilesystemStoreSettings -> Text -> IO FilePath+fsFullMigrationName s name = return $ storePath s </> cs name++isMigrationFilename :: String -> Bool+isMigrationFilename path = (cs $ takeExtension path) `elem` [filenameExtension, filenameExtensionTxt]+ -- |Given a store and migration name, read and parse the associated -- migration and return the migration if successful.  Otherwise return -- a parsing error message.-migrationFromFile :: FilesystemStoreSettings -> String -> IO (Either String Migration)+migrationFromFile :: FilesystemStoreSettings -> Text -> IO (Either String Migration) migrationFromFile store name =-    fsFullMigrationName store name >>= migrationFromPath+    fsFullMigrationName store (cs name) >>= migrationFromPath  -- |Given a filesystem path, read and parse the file as a migration -- return the 'Migration' if successful.  Otherwise return a parsing -- error message. migrationFromPath :: FilePath -> IO (Either String Migration) migrationFromPath path = do-  let name = takeBaseName $ takeFileName path+  let name = cs $ takeBaseName path   (Right <$> process name) `catch` (\(FilesystemStoreError s) -> return $ Left $ "Could not parse migration " ++ path ++ ":" ++ s)    where+    readMigrationFile = do+      ymlExists <- doesFileExist (addNewMigrationExtension path)+      if ymlExists+        then decodeFileThrow (addNewMigrationExtension path) `catch` (\(e::ParseException) -> throwFS $ show e)+        else decodeFileThrow (addMigrationExtension path filenameExtensionTxt) `catch` (\(e::ParseException) -> throwFS $ show e)+     process name = do-      yaml <- parseYamlFile path `catch` (\(e::IOException) -> throwFS $ show e)+      yaml <- readMigrationFile        -- Convert yaml structure into basic key/value map       let fields = getFields yaml@@ -104,14 +124,16 @@             Just m -> return m         _ -> throwFS $ "Error in " ++ (show path) ++ ": missing required field(s): " ++ (show missing) -getFields :: YamlLight -> [(String, String)]-getFields (YMap mp) = map toPair $ Map.assocs mp+getFields :: J.Object -> [(Text, Text)]+getFields mp = map toPair $ M.toList mp     where-      toPair (YStr k, YStr v) = (unpack k, unpack v)+      toPair :: (Text, Value) -> (Text, Text)+      toPair (k, J.String v) = (cs k, cs v)+      toPair (k, J.Null) = (cs k, cs ("" :: String))       toPair (k, v) = throwFS $ "Error in YAML input; expected string key and string value, got " ++ (show (k, v)) getFields _ = throwFS "Error in YAML input; expected mapping" -missingFields :: [(String, String)] -> [String]+missingFields :: [(Text, Text)] -> [Text] missingFields fs =     [ k | k <- requiredFields, not (k `elem` inputStrings) ]     where@@ -119,19 +141,19 @@  -- |Given a migration and a list of parsed migration fields, update -- the migration from the field values for recognized fields.-migrationFromFields :: Migration -> [(String, String)] -> Maybe Migration+migrationFromFields :: Migration -> [(Text, Text)] -> Maybe Migration migrationFromFields m [] = Just m migrationFromFields m ((name, value):rest) = do   processor <- lookup name fieldProcessors   newM <- processor value m   migrationFromFields newM rest -requiredFields :: [String]+requiredFields :: [Text] requiredFields = [ "Apply"                  , "Depends"                  ] -fieldProcessors :: [(String, FieldProcessor)]+fieldProcessors :: [(Text, FieldProcessor)] fieldProcessors = [ ("Created", setTimestamp )                   , ("Description", setDescription )                   , ("Apply", setApply )@@ -146,8 +168,8 @@           _ -> fail "expected one valid parse"   return $ m { mTimestamp = Just ts } -readTimestamp :: String -> [(UTCTime, String)]-readTimestamp = reads+readTimestamp :: Text -> [(UTCTime, String)]+readTimestamp = reads . cs  setDescription :: FieldProcessor setDescription desc m = Just $ m { mDesc = Just desc }@@ -159,4 +181,4 @@ setRevert revert m = Just $ m { mRevert = Just revert }  setDepends :: FieldProcessor-setDepends depString m = Just $ m { mDeps = words depString }+setDepends depString m = Just $ m { mDeps = T.words depString }
src/Database/Schema/Migrations/Filesystem/Serialize.hs view
@@ -1,17 +1,23 @@+{-# LANGUAGE OverloadedStrings #-} module Database.Schema.Migrations.Filesystem.Serialize     ( serializeMigration     ) where +import Data.ByteString ( ByteString )+import qualified Data.ByteString as BS+import Data.Text ( Text )+import qualified Data.Text as T+import Data.String.Conversions ( cs ) import Data.Time () -- for UTCTime Show instance import Data.Maybe ( catMaybes )-import Data.List ( intercalate )+import Data.Monoid ( (<>) )  import Database.Schema.Migrations.Migration     ( Migration(..)     ) -type FieldSerializer = Migration -> Maybe String+type FieldSerializer = Migration -> Maybe ByteString  fieldSerializers :: [FieldSerializer] fieldSerializers = [ serializeDesc@@ -25,48 +31,48 @@ serializeDesc m =     case mDesc m of       Nothing -> Nothing-      Just desc -> Just $ "Description: " ++ desc+      Just desc -> Just . cs $ "Description: " <> desc  serializeTimestamp :: FieldSerializer serializeTimestamp m =     case mTimestamp m of         Nothing -> Nothing-        Just ts -> Just $ "Created: " ++ (show ts)+        Just ts -> Just $ "Created: " <> (cs . show $ ts)  serializeDepends :: FieldSerializer-serializeDepends m = Just $ "Depends: " ++ (intercalate " " $ mDeps m)+serializeDepends m = Just . cs $ "Depends: " <> (T.intercalate " " $ mDeps m)  serializeRevert :: FieldSerializer serializeRevert m =     case mRevert m of       Nothing -> Nothing-      Just revert -> Just $ "Revert: |\n" +++      Just revert -> Just $ "Revert: |\n" <>                      (serializeMultiline revert)  serializeApply :: FieldSerializer-serializeApply m = Just $ "Apply: |\n" ++ (serializeMultiline $ mApply m)+serializeApply m = Just $ "Apply: |\n" <> (serializeMultiline $ mApply m) -commonPrefix :: String -> String -> String-commonPrefix a b = map fst $ takeWhile (uncurry (==)) (zip a b)+commonPrefix :: Text -> Text -> Text+commonPrefix a b = cs . map fst $ takeWhile (uncurry (==)) (T.zip a b) -commonPrefixLines :: [String] -> String+commonPrefixLines :: [Text] -> Text commonPrefixLines [] = "" commonPrefixLines theLines = foldl1 commonPrefix theLines -serializeMultiline :: String -> String+serializeMultiline :: Text -> ByteString serializeMultiline s =-    let sLines = lines s-        prefix = case commonPrefixLines sLines of+    let sLines = T.lines s+        prefix = case T.head $ commonPrefixLines sLines of                    -- If the lines already have a common prefix that                    -- begins with whitespace, no new prefix is                    -- necessary.-                   (' ':_) -> ""+                   ' ' -> ""                    -- Otherwise, use a new prefix of two spaces.                    _ -> "  " -    in unlines $ map (prefix ++) sLines+    in cs . T.unlines $ map (prefix <>) sLines -serializeMigration :: Migration -> String-serializeMigration m = intercalate "\n" fields+serializeMigration :: Migration -> ByteString+serializeMigration m = BS.intercalate "\n" fields     where       fields = catMaybes [ f m | f <- fieldSerializers ]
src/Database/Schema/Migrations/Migration.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module Database.Schema.Migrations.Migration     ( Migration(..)     , newMigration@@ -7,15 +8,16 @@  import Database.Schema.Migrations.Dependencies +import Data.Text ( Text ) import Data.Time () -- for UTCTime Show instance import qualified Data.Time.Clock as Clock  data Migration = Migration { mTimestamp :: Maybe Clock.UTCTime-                           , mId :: String-                           , mDesc :: Maybe String-                           , mApply :: String-                           , mRevert :: Maybe String-                           , mDeps :: [String]+                           , mId :: Text+                           , mDesc :: Maybe Text+                           , mApply :: Text+                           , mRevert :: Maybe Text+                           , mDeps :: [Text]                            }                deriving (Eq, Show, Ord) @@ -23,7 +25,7 @@     depsOf = mDeps     depId = mId -emptyMigration :: String -> Migration+emptyMigration :: Text -> Migration emptyMigration name =   Migration { mTimestamp = Nothing             , mId = name@@ -33,7 +35,7 @@             , mDeps = []             } -newMigration :: String -> Migration+newMigration :: Text -> Migration newMigration theId =    (emptyMigration theId)      { mApply = "(Apply SQL here.)"
src/Database/Schema/Migrations/Store.hs view
@@ -23,6 +23,7 @@     ) where +import Data.Text ( Text ) import Data.Maybe ( isJust ) import Control.Monad ( mzero ) import Control.Applicative ( (<$>) )@@ -41,7 +42,7 @@ -- |A mapping from migration name to 'Migration'.  This is exported -- for testing purposes, but you'll want to interface with this -- through the encapsulating 'StoreData' type.-type MigrationMap = Map.Map String Migration+type MigrationMap = Map.Map Text Migration  data StoreData = StoreData { storeDataMapping :: MigrationMap                            , storeDataGraph :: DependencyGraph Migration@@ -51,17 +52,17 @@ -- facility in which new migrations can be created, and from which -- existing migrations can be loaded. data MigrationStore =-    MigrationStore { loadMigration :: String -> IO (Either String Migration)+    MigrationStore { loadMigration :: Text -> IO (Either String Migration)                    -- ^ Load a migration from the store.                     , saveMigration :: Migration -> IO ()                    -- ^ Save a migration to the store. -                   , getMigrations :: IO [String]+                   , getMigrations :: IO [Text]                    -- ^ Return a list of all available migrations'                    -- names. -                   , fullMigrationName :: String -> IO String+                   , fullMigrationName :: Text -> IO FilePath                    -- ^ Return the full representation of a given                    -- migration name; mostly for filesystem stores,                    -- where the full representation includes the store@@ -69,7 +70,7 @@                    }  -- |A type for types of validation errors for migration maps.-data MapValidationError = DependencyReferenceError String String+data MapValidationError = DependencyReferenceError Text Text                           -- ^ A migration claims a dependency on a                           -- migration that does not exist.                         | DependencyGraphError String@@ -96,7 +97,7 @@  -- |A convenience function for looking up a 'Migration' by name in the -- specified 'StoreData'.-storeLookup :: StoreData -> String -> Maybe Migration+storeLookup :: StoreData -> Text -> Maybe Migration storeLookup storeData migrationName =     Map.lookup migrationName $ storeDataMapping storeData @@ -153,6 +154,6 @@  -- |Finds migrations that no other migration depends on (effectively finds all -- vertices with in-degree equal to zero).-leafMigrations :: StoreData -> [String]+leafMigrations :: StoreData -> [Text] leafMigrations s = [l | (n, l) <- labNodes g, indeg g n == 0]     where g = depGraph $ storeDataGraph s
src/Database/Schema/Migrations/Test/BackendTest.hs view
@@ -9,6 +9,8 @@     , tests     ) where +import Data.ByteString ( ByteString )+ import Control.Monad ( forM_ ) import Test.HUnit @@ -30,7 +32,7 @@     withTransaction :: c -> (c -> IO a) -> IO a      -- | Retrieves a list of all tables in the current database/scheme.-    getTables :: c -> IO [String]+    getTables :: c -> IO [ByteString]      catchAll :: c -> (IO a -> IO a -> IO a) @@ -102,7 +104,7 @@         m2 = (newMigration "third") { mApply = "INVALID SQL" }      -- Apply the migrations, ignore exceptions-    ignoreSqlExceptions conn $ withTransaction conn $ \conn' -> do+    _ <- ignoreSqlExceptions conn $ withTransaction conn $ \conn' -> do         let backend' = makeBackend conn'         applyMigration backend' m1         applyMigration backend' m2@@ -129,7 +131,7 @@      -- Revert the migrations, ignore exceptions; the revert will fail,     -- but withTransaction will roll back.-    ignoreSqlExceptions conn $ withTransaction conn $ \conn' -> do+    _ <- ignoreSqlExceptions conn $ withTransaction conn $ \conn' -> do         let backend' = makeBackend conn'         revertMigration backend' m2         revertMigration backend' m1
src/Moo/CommandHandlers.hs view
@@ -3,6 +3,8 @@ {-# LANGUAGE OverloadedStrings #-} module Moo.CommandHandlers where +import Data.String.Conversions (cs, (<>))+ import Moo.Core import Moo.CommandUtils import Control.Monad ( when, forM_ )@@ -23,10 +25,10 @@   store      <- asks _appStore   linear     <- asks _appLinearMigrations   timestamp  <- asks _appTimestampFilenames-  timeString <- (++"_") <$> liftIO getCurrentTimestamp+  timeString <- (<>"_") <$> liftIO getCurrentTimestamp    let [migrationId] = if timestamp-      then fmap (timeString++) required+      then fmap (timeString<>) required       else required   noAsk <- _noAsk <$> asks _appOptions @@ -34,15 +36,15 @@     fullPath <- fullMigrationName store migrationId     when (isJust $ storeLookup storeData migrationId) $          do-           putStrLn $ "Migration " ++ (show fullPath) ++ " already exists"+           putStrLn $ "Migration " <> (show fullPath) ++ " already exists"            exitWith (ExitFailure 1)      -- Default behavior: ask for dependencies if linear mode is disabled     deps <- if linear then (return $ leafMigrations storeData) else            if noAsk then (return []) else            do-             putStrLn $ "Selecting dependencies for new \-                        \migration: " ++ migrationId+             putStrLn . cs $ "Selecting dependencies for new \+                        \migration: " <> migrationId              interactiveAskDeps storeData      result <- if noAsk then (return True) else@@ -90,7 +92,7 @@                                putStrLn "Database is up to date."                                exitSuccess         putStrLn "Migrations to install:"-        forM_ migrationNames (putStrLn . ("  " ++))+        forM_ migrationNames (putStrLn . cs . ("  " <>))  reinstallCommand :: CommandHandler reinstallCommand storeData = do@@ -102,8 +104,8 @@       ensureBootstrappedBackend backend >> commitBackend backend       m <- lookupMigration storeData migrationId -      revert m storeData backend-      apply m storeData backend True+      _ <- revert m storeData backend+      _ <- apply m storeData backend True        case isTesting of         False -> do@@ -119,7 +121,7 @@       ensureBootstrappedBackend backend >> commitBackend backend       ms <- getMigrations backend       forM_ ms $ \m ->-          when (not $ m == rootMigrationName) $ putStrLn m+          when (not $ m == rootMigrationName) $ putStrLn . cs $ m  applyCommand :: CommandHandler applyCommand storeData = do@@ -130,7 +132,7 @@   withBackend $ \backend -> do         ensureBootstrappedBackend backend >> commitBackend backend         m <- lookupMigration storeData migrationId-        apply m storeData backend True+        _ <- apply m storeData backend True         case isTesting of           False -> do             commitBackend backend@@ -148,7 +150,7 @@   withBackend $ \backend -> do       ensureBootstrappedBackend backend >> commitBackend backend       m <- lookupMigration storeData migrationId-      revert m storeData backend+      _ <- revert m storeData backend        case isTesting of         False -> do@@ -170,7 +172,7 @@         -- If the migration is already installed, remove it as part of         -- the test         when (not $ migrationId `elem` migrationNames) $-             do revert m storeData backend+             do _ <- revert m storeData backend                 return ()         applied <- apply m storeData backend True         forM_ (reverse applied) $ \migration -> do
src/Moo/CommandUtils.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleContexts, OverloadedStrings #-} module Moo.CommandUtils        ( apply        , confirmCreation@@ -9,7 +9,10 @@        , getCurrentTimestamp        ) where -import Control.Applicative+import Data.Text ( Text )+import qualified Data.Text as T+import Data.String.Conversions ( cs, (<>) )+ import Control.Exception ( finally ) import Control.Monad ( when, forM_, unless ) import Control.Monad.Reader ( asks )@@ -30,9 +33,9 @@                                         ) import Moo.Core -getCurrentTimestamp :: IO String+getCurrentTimestamp :: IO Text getCurrentTimestamp =-  replace ":" "-" . replace " " "_" . take 19 . show <$> getCurrentTime+  cs . replace ":" "-" . replace " " "_" . take 19 . show <$> getCurrentTime  apply :: Migration -> StoreData -> Backend -> Bool -> IO [Migration] apply m storeData backend complain = do@@ -47,12 +50,12 @@     where       nothingToDo =         when complain $-             putStrLn $ "Nothing to do; " ++-                          mId m +++             putStrLn . cs $ "Nothing to do; " <>+                          mId m <>                           " already installed."        applyIt conn it = do-        putStr $ "Applying: " ++ mId it ++ "... "+        putStr . cs $ "Applying: " <> mId it <> "... "         applyMigration conn it         putStrLn "done." @@ -68,22 +71,22 @@      where       nothingToDo =-        putStrLn $ "Nothing to do; " ++-                 mId m +++        putStrLn . cs $ "Nothing to do; " <>+                 mId m <>                  " not installed."        revertIt conn it = do-        putStr $ "Reverting: " ++ mId it ++ "... "+        putStr . cs $ "Reverting: " <> mId it <> "... "         revertMigration conn it         putStrLn "done."  -lookupMigration :: StoreData -> String -> IO Migration+lookupMigration :: StoreData -> Text -> IO Migration lookupMigration storeData name = do   let theMigration = storeLookup storeData name   case theMigration of     Nothing -> do-      putStrLn $ "No such migration: " ++ name+      putStrLn . cs $ "No such migration: " <> name       exitWith (ExitFailure 1)     Just m' -> return m' @@ -97,13 +100,13 @@  -- Given a migration name and selected dependencies, get the user's -- confirmation that a migration should be created.-confirmCreation :: String -> [String] -> IO Bool+confirmCreation :: Text -> [Text] -> IO Bool confirmCreation migrationId deps = do   putStrLn ""-  putStrLn $ "Confirm: create migration '" ++ migrationId ++ "'"+  putStrLn . cs $ "Confirm: create migration '" <> migrationId <> "'"   if null deps then putStrLn "  (No dependencies)"      else putStrLn "with dependencies:"-  forM_ deps $ \d -> putStrLn $ "  " ++ d+  forM_ deps $ \d -> putStrLn . cs $ "  " <> d   prompt "Are you sure?" [ ('y', (True, Nothing))                          , ('n', (False, Nothing))                          ]@@ -162,7 +165,7 @@  -- Interactively ask the user about which dependencies should be used -- when creating a new migration.-interactiveAskDeps :: StoreData -> IO [String]+interactiveAskDeps :: StoreData -> IO [Text] interactiveAskDeps storeData = do   -- For each migration in the store, starting with the most recently   -- added, ask the user if it should be added to a dependency list@@ -174,10 +177,10 @@ -- Recursive function to prompt the user for dependencies and let the -- user view information about potential dependencies.  Returns a list -- of migration names which were selected.-interactiveAskDeps' :: StoreData -> [String] -> IO [String]+interactiveAskDeps' :: StoreData -> [Text] -> IO [Text] interactiveAskDeps' _ [] = return [] interactiveAskDeps' storeData (name:rest) = do-  result <- prompt ("Depend on '" ++ name ++ "'?") askDepsChoices+  result <- prompt ("Depend on '" ++ cs name ++ "'?") askDepsChoices   if result == Done then return [] else         case result of           Yes -> do@@ -189,12 +192,12 @@             let Just m = storeLookup storeData name             -- print out description, timestamp, deps             when (isJust $ mDesc m)-                     (putStrLn $ "  Description: " +++                     (putStrLn . cs $ "  Description: " <>                                     fromJust  (mDesc m))             putStrLn $ "      Created: " ++ show (mTimestamp m)             unless (null $ mDeps m)-                     (putStrLn $ "  Deps: " ++-                                   intercalate "\n        "  (mDeps m))+                     (putStrLn . cs $ "  Deps: " <>+                                   T.intercalate "\n        "  (mDeps m))             -- ask again             interactiveAskDeps' storeData (name:rest)           Quit -> do
src/Moo/Core.hs view
@@ -13,7 +13,8 @@     , envStoreName     , loadConfiguration) where -import Control.Applicative+import Data.Text ( Text )+ import Control.Monad.Reader (ReaderT) import qualified Data.Configurator as C import Data.Configurator.Types (Config, Configured)@@ -34,8 +35,8 @@ -- |Application state which can be accessed by any command handler. data AppState = AppState { _appOptions            :: CommandOptions                          , _appCommand            :: Command-                         , _appRequiredArgs       :: [String]-                         , _appOptionalArgs       :: [String]+                         , _appRequiredArgs       :: [Text]+                         , _appOptionalArgs       :: [Text]                          , _appBackend            :: Backend                          , _appStore              :: MigrationStore                          , _appStoreData          :: StoreData
src/Moo/Main.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module Moo.Main     ( mainWithParameters     , ExecutableParameters (..)@@ -12,6 +13,8 @@ import  Control.Monad.Reader (forM_, runReaderT, when) import  Database.HDBC (SqlError, catchSql, seErrorMsg) import  Prelude  hiding (lookup)+import  Data.Text (Text)+import  Data.String.Conversions (cs) import  System.Environment (getProgName) import  System.Exit (ExitCode (ExitFailure), exitWith) @@ -77,8 +80,8 @@           Right storeData -> do             let st = AppState { _appOptions = opts                               , _appCommand = command-                              , _appRequiredArgs = required-                              , _appOptionalArgs = ["" :: String]+                              , _appRequiredArgs = map cs required+                              , _appOptionalArgs = ["" :: Text]                               , _appBackend = _parametersBackend parameters                               , _appStore = store                               , _appStoreData = storeData
test/Common.hs view
@@ -8,6 +8,8 @@     ) where +import Data.Text ( Text )+ import CommonTH import System.FilePath ( (</>) ) import Language.Haskell.TH.Syntax (lift)@@ -25,8 +27,8 @@     depId = tdId     depsOf = tdDeps -data TestDependable = TD { tdId :: String-                         , tdDeps :: [String]+data TestDependable = TD { tdId :: Text+                         , tdDeps :: [Text]                          }                       deriving (Show, Eq, Ord) 
test/DependencyTest.hs view
@@ -1,8 +1,11 @@+{-# LANGUAGE OverloadedStrings #-} module DependencyTest     ( tests     ) where +import Data.Text ( Text )+ import Test.HUnit import Data.Graph.Inductive.Graph ( Graph(..) ) @@ -39,7 +42,7 @@ mkDepGraphTest (input, expected) = expected ~=? mkDepGraph input  data Direction = Forward | Reverse deriving (Show)-type DependencyTestCase = ([TestDependable], String, Direction, [String])+type DependencyTestCase = ([TestDependable], Text, Direction, [Text])  dependencyTestCases :: [DependencyTestCase] dependencyTestCases = [ ([TD "first" []], "first", Forward, [])
test/FilesystemParseTest.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module FilesystemParseTest     ( tests     )@@ -6,6 +7,7 @@ import Test.HUnit import Data.Time.Clock ( UTCTime ) import System.FilePath ( (</>) )+import Data.String.Conversions ( cs )  import Common @@ -84,34 +86,33 @@                               , Right (valid_full { mId = "valid_no_timestamp", mTimestamp = Nothing }))                             , ("invalid_missing_required_fields"                               , Left $ "Could not parse migration " ++-                                         (fp "invalid_missing_required_fields.txt") +++                                         (fp "invalid_missing_required_fields") ++                                          ":Error in " ++-                                         (show $ fp "invalid_missing_required_fields.txt") +++                                         (show $ fp "invalid_missing_required_fields") ++                                          ": missing required field(s): " ++                                          "[\"Depends\"]")                             , ("invalid_field_name"                               , Left $ "Could not parse migration " ++-                                         (fp "invalid_field_name.txt") +++                                         (fp "invalid_field_name") ++                                          ":Error in " ++-                                         (show $ fp "invalid_field_name.txt") +++                                         (show $ fp "invalid_field_name") ++                                          ": unrecognized field found")                             , ("invalid_syntax"                               , Left $ "Could not parse migration " ++-                                         (fp "invalid_syntax.txt") ++-                                         ":user error (syntax error: line 7, " ++-                                         "column 0)")+                                         (fp "invalid_syntax") +++                                         ":InvalidYaml (Just (YamlParseException {yamlProblem = \"could not find expected ':'\", yamlContext = \"while scanning a simple key\", yamlProblemMark = YamlMark {yamlIndex = 130, yamlLine = 6, yamlColumn = 0}}))")                             , ("invalid_timestamp"                               , Left $ "Could not parse migration " ++-                                         (fp "invalid_timestamp.txt") +++                                         (fp "invalid_timestamp") ++                                          ":Error in " ++-                                         (show $ fp "invalid_timestamp.txt") +++                                         (show $ fp "invalid_timestamp") ++                                          ": unrecognized field found")                             ]  mkParsingTest :: MigrationParsingTestCase -> IO Test mkParsingTest (fname, expected) = do   let store = FSStore { storePath = testStorePath }-  actual <- migrationFromFile store fname+  actual <- migrationFromFile store (cs fname)   return $ test $ expected ~=? actual  migrationParsingTests :: IO [Test]
test/FilesystemSerializeTest.hs view
@@ -1,9 +1,12 @@+{-# LANGUAGE OverloadedStrings #-} module FilesystemSerializeTest     ( tests     ) where  import Test.HUnit+import Data.ByteString ( ByteString )+import Data.String.Conversions ( (<>), cs ) import Data.Time.Clock ( UTCTime )  import Database.Schema.Migrations.Filesystem.Serialize@@ -12,7 +15,7 @@ tests :: [Test] tests = serializationTests -mkSerializationTest :: (Migration, String) -> Test+mkSerializationTest :: (Migration, ByteString) -> Test mkSerializationTest (m, expectedString) = test $ expectedString ~=? serializeMigration m  tsStr :: String@@ -31,9 +34,9 @@              , mRevert = Just "DROP TABLE test;"              } -serializationTestCases :: [(Migration, String)]-serializationTestCases = [ (valid_full, "Description: A valid full migration.\n\-                                        \Created: " ++ tsStr ++ "\n\+serializationTestCases :: [(Migration, ByteString)]+serializationTestCases = [ (valid_full, cs $ "Description: A valid full migration.\n\+                                        \Created: " <> tsStr <> "\n\                                         \Depends: another_migration\n\                                         \Apply: |\n\                                         \  CREATE TABLE test (\n\@@ -42,7 +45,7 @@                                         \Revert: |\n\                                         \  DROP TABLE test;\n")                          , (valid_full { mDesc = Nothing }-                           , "Created: " ++ tsStr ++ "\n\+                           , cs $ "Created: " <> tsStr <> "\n\                              \Depends: another_migration\n\                              \Apply: |\n\                              \  CREATE TABLE test (\n\@@ -51,8 +54,8 @@                              \Revert: |\n\                              \  DROP TABLE test;\n")                          , (valid_full { mDeps = ["one", "two"] }-                           , "Description: A valid full migration.\n\-                             \Created: " ++ tsStr ++ "\n\+                           , cs $ "Description: A valid full migration.\n\+                             \Created: " <> tsStr <> "\n\                              \Depends: one two\n\                              \Apply: |\n\                              \  CREATE TABLE test (\n\@@ -61,8 +64,8 @@                              \Revert: |\n\                              \  DROP TABLE test;\n")                          , (valid_full { mRevert = Nothing }-                           , "Description: A valid full migration.\n\-                             \Created: " ++ tsStr ++ "\n\+                           , cs $ "Description: A valid full migration.\n\+                             \Created: " <> tsStr <> "\n\                              \Depends: another_migration\n\                              \Apply: |\n\                              \  CREATE TABLE test (\n\
test/FilesystemTest.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module FilesystemTest     ( tests     )
test/InMemoryStore.hs view
@@ -1,10 +1,13 @@ module InMemoryStore (inMemoryStore) where +import Data.Text ( Text )+import Data.String.Conversions ( cs )+ import           Control.Concurrent.MVar import           Database.Schema.Migrations.Migration import           Database.Schema.Migrations.Store -type InMemoryData = [(String, Migration)]+type InMemoryData = [(Text, Migration)]  -- |Builds simple in-memory store that uses 'MVar' to preserve a list of -- migrations.@@ -15,10 +18,10 @@       loadMigration = loadMigrationInMem store     , saveMigration = saveMigrationInMem store     , getMigrations = getMigrationsInMem store-    , fullMigrationName = return+    , fullMigrationName = return . cs     } -loadMigrationInMem :: MVar InMemoryData -> String -> IO (Either String Migration)+loadMigrationInMem :: MVar InMemoryData -> Text -> IO (Either String Migration) loadMigrationInMem store migId = withMVar store $ \migrations -> do     let mig = lookup migId migrations     return $ case mig of@@ -28,5 +31,5 @@ saveMigrationInMem :: MVar InMemoryData -> Migration -> IO () saveMigrationInMem store m = modifyMVar_ store $ return . ((mId m, m):) -getMigrationsInMem :: MVar InMemoryData -> IO [String]+getMigrationsInMem :: MVar InMemoryData -> IO [Text] getMigrationsInMem store = withMVar store $ return . fmap fst
test/LinearMigrationsTest.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module LinearMigrationsTest (tests) where  import           InMemoryStore@@ -5,6 +6,7 @@  import           Common import           Control.Monad.Reader                 (runReaderT)+import           Data.Text                            (Text) import           Data.Either                          (isRight) import           Database.Schema.Migrations.Migration import           Database.Schema.Migrations.Store@@ -60,13 +62,13 @@     runReaderT (newCommand $ _appStoreData state) state     loadMigration store migrationId -addTestMigrationWithDeps :: AppState -> [String] -> IO ()+addTestMigrationWithDeps :: AppState -> [Text] -> IO () addTestMigrationWithDeps state deps = do     let store = _appStore state     let [migrationId] = _appRequiredArgs state     saveMigration store (newMigration migrationId) { mDeps = deps } -prepareState :: String -> IO AppState+prepareState :: Text -> IO AppState prepareState m = do     store <- inMemoryStore     Right storeData <- loadMigrations store@@ -82,12 +84,12 @@     , _appTimestampFilenames = False     } -prepareStateWith :: AppState -> String -> IO AppState+prepareStateWith :: AppState -> Text -> IO AppState prepareStateWith state m = do     Right storeData <- loadMigrations $ _appStore state     return state { _appRequiredArgs = [m], _appStoreData = storeData } -prepareNormalState :: String -> IO AppState+prepareNormalState :: Text -> IO AppState prepareNormalState m = do     state <- prepareState m     return $ state { _appLinearMigrations = False }
+ test/Main.hs view
@@ -0,0 +1,51 @@+module Main where+import Prelude+import Test.HUnit+import System.Exit+import System.IO ( stderr )++import qualified DependencyTest+import qualified MigrationsTest+import qualified FilesystemSerializeTest+import qualified FilesystemParseTest+import qualified FilesystemTest+import qualified CycleDetectionTest+import qualified StoreTest+import qualified LinearMigrationsTest+import qualified ConfigurationTest++import Control.Exception ( SomeException(..) )++loadTests :: IO [Test]+loadTests = do++  ioTests <- sequence [ do fspTests <- FilesystemParseTest.tests+                           return $ "Filesystem Parsing" ~: test fspTests+                      , do fsTests <- FilesystemTest.tests+                           return $ "Filesystem general" ~: test fsTests+                      , do linTests <- LinearMigrationsTest.tests+                           return $ "Linear migrations" ~: test linTests+                      , do cfgTests <- ConfigurationTest.tests+                           return $ "Configuration tests" ~: test cfgTests+                      ]+  return $ concat [ ioTests+                  , DependencyTest.tests+                  , FilesystemSerializeTest.tests+                  , MigrationsTest.tests+                  , CycleDetectionTest.tests+                  , StoreTest.tests+                  ]++tempDatabase :: String+tempDatabase = "dbmigrations_test"++ignoreException :: SomeException -> IO ()+ignoreException _ = return ()++main :: IO ()+main = do+  tests <- loadTests+  (testResults, _) <- runTestText (putTextToHandle stderr False) $ test tests+  if errors testResults + failures testResults > 0+    then exitFailure+    else exitSuccess
test/MigrationsTest.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE TypeSynonymInstances,GeneralizedNewtypeDeriving,MultiParamTypeClasses,FlexibleInstances #-}+{-# LANGUAGE TypeSynonymInstances,GeneralizedNewtypeDeriving,MultiParamTypeClasses,FlexibleInstances,OverloadedStrings #-} module MigrationsTest     ( tests     )
test/StoreTest.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} module StoreTest     ( tests     )
− test/TestDriver.hs
@@ -1,51 +0,0 @@-module Main where-import Prelude-import Test.HUnit-import System.Exit-import System.IO ( stderr )--import qualified DependencyTest-import qualified MigrationsTest-import qualified FilesystemSerializeTest-import qualified FilesystemParseTest-import qualified FilesystemTest-import qualified CycleDetectionTest-import qualified StoreTest-import qualified LinearMigrationsTest-import qualified ConfigurationTest--import Control.Exception ( SomeException(..) )--loadTests :: IO [Test]-loadTests = do--  ioTests <- sequence [ do fspTests <- FilesystemParseTest.tests-                           return $ "Filesystem Parsing" ~: test fspTests-                      , do fsTests <- FilesystemTest.tests-                           return $ "Filesystem general" ~: test fsTests-                      , do linTests <- LinearMigrationsTest.tests-                           return $ "Linear migrations" ~: test linTests-                      , do cfgTests <- ConfigurationTest.tests-                           return $ "Configuration tests" ~: test cfgTests-                      ]-  return $ concat [ ioTests-                  , DependencyTest.tests-                  , FilesystemSerializeTest.tests-                  , MigrationsTest.tests-                  , CycleDetectionTest.tests-                  , StoreTest.tests-                  ]--tempDatabase :: String-tempDatabase = "dbmigrations_test"--ignoreException :: SomeException -> IO ()-ignoreException _ = return ()--main :: IO ()-main = do-  tests <- loadTests-  (testResults, _) <- runTestText (putTextToHandle stderr False) $ test tests-  if errors testResults + failures testResults > 0-    then exitFailure-    else exitSuccess