Skip to content

Commit

Permalink
Migration path Env Var. (#2015)
Browse files Browse the repository at this point in the history
* changed migrations path to detect an environemnt variable or use default.

* updated docs.

* updated options and migrate.nix.

* fix lifting cs into IO.

* updates to ihp.nix

* recommenting testing flags in ihp.nix
  • Loading branch information
Montmorency authored Nov 19, 2024
1 parent a30f725 commit f59b36f
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 25 deletions.
14 changes: 14 additions & 0 deletions Guide/database-migrations.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ migrate

A good value for `MINIMUM_REVISION` is typically the unix timestamp of the time when the database was initially created.


### IHP MIGRATIONS DIR

In production when running the migrations binary it is sometimes convenient to have all your Migrations in a non-standard place:
e.g. if you need to push migrations onto production server without rebuilding the application. There is an Environment variable
`IHP_MIGRATION_DIR` to accomplish this.

```
IHP_MIGRATION_DIR=path/to/my/migration/dir
```

This can be set in the environment attribute set of your IHP app flake.


## Common Issues

### ALTER TYPE ... ADD cannot run inside a transaction block
Expand Down
11 changes: 8 additions & 3 deletions IHP/SchemaMigration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import qualified Data.Text.IO as Text
import IHP.ModelSupport hiding (withTransaction)
import qualified Data.Char as Char
import IHP.Log.Types
import IHP.EnvVar

data Migration = Migration
{ revision :: Int
Expand All @@ -37,7 +38,9 @@ migrate options = do
-- All queries are executed inside a database transaction to make sure that it can be restored when something goes wrong.
runMigration :: (?modelContext :: ModelContext) => Migration -> IO ()
runMigration migration@Migration { revision, migrationFile } = do
migrationSql <- Text.readFile (cs $ migrationPath migration)
-- | User can specify migrations directory as environment variable (defaults to /Application/Migrations/...)
migrationFilePath <- migrationPath migration
migrationSql <- Text.readFile (cs migrationFilePath)

let fullSql = [trimming|
BEGIN;
Expand Down Expand Up @@ -123,5 +126,7 @@ pathToMigration fileName = case revision of
|> fmap textToInt
|> join

migrationPath :: Migration -> Text
migrationPath Migration { migrationFile } = "Application/Migration/" <> migrationFile
migrationPath :: Migration -> IO Text
migrationPath Migration { migrationFile } = do
migrationDir <- envOrDefault "IHP_MIGRATION_DIR" "Application/Migration/"
pure (migrationDir <> migrationFile)
36 changes: 21 additions & 15 deletions NixSupport/nixosModules/options.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,63 +13,70 @@ with lib;
type = types.str;
default = "https://${config.services.ihp.domain}";
};

migrations = mkOption {
type = types.path;
};

schema = mkOption {
type = types.path;
};

fixtures = mkOption {
type = types.path;
};

httpsEnabled = mkOption {
type = types.bool;
default = true;
};

databaseName = mkOption {
type = types.str;
default = "app";
};

databaseUser = mkOption {
type = types.str;
default = "ihp";
};

databaseUrl = mkOption {
type = types.str;
};

# https://ihp.digitallyinduced.com/Guide/database-migrations.html#skipping-old-migrations
minimumRevision = mkOption {
type = types.int;
default = 0;
};


# https://ihp.digitallyinduced.com/Guide/database-migrations.html#ihp-migrations-dir
ihpMigrationDir = mkOption {
type = types.str;
default = "Application/Migration/";
};


ihpEnv = mkOption {
type = types.str;
default = "Production";
};

appPort = mkOption {
type = types.int;
default = 8000;
};

requestLoggerIPAddrSource = mkOption {
type = types.str;
default = "FromHeader";
};

sessionSecret = mkOption {
type = types.str;
};

additionalEnvVars = mkOption {
type = types.attrs;
default = {};
Expand All @@ -79,7 +86,7 @@ with lib;
type = types.package;
default = if config.services.ihp.optimized then self.packages."${pkgs.system}".optimized-prod-server else self.packages."${pkgs.system}".default;
};

optimized = mkOption {
type = types.bool;
default = false;
Expand All @@ -91,4 +98,3 @@ with lib;
};
};
}

3 changes: 2 additions & 1 deletion NixSupport/nixosModules/services/migrate.nix
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ in
environment = {
DATABASE_URL = cfg.databaseUrl;
MINIMUM_REVISION = "${toString cfg.minimumRevision}";
IHP_MIGRATION_DIR = cfg.ihpMigrationDir;
};
};
}
}
14 changes: 8 additions & 6 deletions ihp-ide/IHP/IDE/SchemaDesigner/Controller/Migrations.hs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ instance Controller MigrationsController where
let errorMessage = case fromException exception of
Just (exception :: EnhancedSqlError) -> cs exception.sqlError.sqlErrorMsg
Nothing -> tshow exception

setErrorMessage errorMessage
redirectTo MigrationsAction
Right _ -> do
Expand All @@ -79,14 +79,14 @@ instance Controller MigrationsController where
action UpdateMigrationAction { migrationId } = do
migration <- findMigrationByRevision migrationId
let sqlStatements = param "sqlStatements"

Text.writeFile (cs $ SchemaMigration.migrationPath migration) sqlStatements
migrationFilePath <- SchemaMigration.migrationPath migration
Text.writeFile (cs migrationFilePath) sqlStatements

redirectTo MigrationsAction

action DeleteMigrationAction { migrationId } = do
migration <- findMigrationByRevision migrationId
let path = cs $ SchemaMigration.migrationPath migration
path <- cs <$> SchemaMigration.migrationPath migration

Directory.removeFile path

Expand All @@ -101,15 +101,17 @@ instance Controller MigrationsController where
let errorMessage = case fromException exception of
Just (exception :: EnhancedSqlError) -> cs exception.sqlError.sqlErrorMsg
Nothing -> tshow exception

setErrorMessage errorMessage
redirectTo MigrationsAction
Right _ -> do
clearDatabaseNeedsMigration
redirectTo MigrationsAction

readSqlStatements :: SchemaMigration.Migration -> IO Text
readSqlStatements migration = Text.readFile (cs $ SchemaMigration.migrationPath migration)
readSqlStatements migration = do
migrationFilePath <- (SchemaMigration.migrationPath migration)
pure Text.readFile (migrationFilePath)

findRecentMigrations :: IO [SchemaMigration.Migration]
findRecentMigrations = take 20 . reverse <$> SchemaMigration.findAllMigrations
Expand Down

0 comments on commit f59b36f

Please sign in to comment.