Exemplo n.º 1
0
 public MigratorBuilder(IServiceCollection services = null)
 {
     _services               = services ?? new ServiceCollection();
     _migrationsProviders    = new List <IMigrationsProvider>();
     _preMigrationsProviders = new List <IMigrationsProvider>();
     _upgradePolicy          = MigrationPolicy.All;
     _downgradePolicy        = MigrationPolicy.All;
     _targetVersion          = default;
     _variables              = new Dictionary <string, string>();
 }
Exemplo n.º 2
0
        /// <summary>
        /// Check permission to migrate using specified policy
        /// </summary>
        /// <param name="versionDifference"></param>
        /// <param name="policy"></param>
        /// <returns></returns>
        private bool IsMigrationAllowed(DbVersionDifference versionDifference, MigrationPolicy policy)
        {
            switch (versionDifference)
            {
            case DbVersionDifference.Major:
                return(policy.HasFlag(MigrationPolicy.Major));

            case DbVersionDifference.Minor:
                return(policy.HasFlag(MigrationPolicy.Minor));

            default:
                return(false);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Default realisation of <see cref="IDbMigrator"/>
        /// </summary>
        /// <param name="dbProvider">Provider for database</param>
        /// <param name="migrations">Main migrations for changing database</param>
        /// <param name="upgradePolicy">Policy for upgrading database</param>
        /// <param name="downgradePolicy">Policy for downgrading database</param>
        /// <param name="preMigrations">Migrations that will be executed before <paramref name="migrations"/></param>
        /// <param name="targetVersion">Desired version of database after migration. If <see langword="null"/> migrator will upgrade database to the most actual version</param>
        /// <param name="logger">Optional logger</param>
        public DbMigrator(
            IDbProvider dbProvider,
            ICollection <IMigration> migrations,
            MigrationPolicy upgradePolicy,
            MigrationPolicy downgradePolicy,
            ICollection <IMigration> preMigrations = null,
            DbVersion?targetVersion = null,
            ILogger logger          = null)
        {
            if (migrations == null)
            {
                throw new ArgumentNullException(nameof(migrations));
            }
            _dbProvider = dbProvider ?? throw new ArgumentNullException(nameof(dbProvider));

            _migrations = migrations.ToList();

            var migrationCheckMap = new HashSet <DbVersion>();

            foreach (var migration in _migrations)
            {
                if (migrationCheckMap.Contains(migration.Version))
                {
                    throw new InvalidOperationException(
                              $"There is more than one migration with version {migration.Version}");
                }

                migrationCheckMap.Add(migration.Version);
            }

            _upgradePolicy   = upgradePolicy;
            _downgradePolicy = downgradePolicy;
            _preMigrations   = preMigrations ?? new List <IMigration>(0);
            _targetVersion   = targetVersion;
            _logger          = logger;
        }
Exemplo n.º 4
0
        private async Task MigrateAsync(IReadOnlyCollection <IMigration> orderedMigrations, bool isUpgrade, MigrationPolicy policy, CancellationToken token = default)
        {
            if (policy == MigrationPolicy.Forbidden)
            {
                throw new MigrationException(MigrationError.PolicyError, $"{(isUpgrade ? "Upgrading": "Downgrading")} is forbidden due to migration policy");
            }

            if (orderedMigrations.Count == 0)
            {
                return;
            }

            var operationName = isUpgrade
                ? "Upgrade"
                : "Downgrade";

            foreach (var migration in orderedMigrations)
            {
                token.ThrowIfCancellationRequested();

                DbTransaction?transaction = null;

                try
                {
                    // sometimes transactions fails without reopening connection
                    //todo #19: fix it later
                    await _dbProvider.CloseConnectionAsync();

                    await _dbProvider.OpenConnectionAsync(token);

                    if (migration.IsTransactionRequired)
                    {
                        transaction = _dbProvider.BeginTransaction();
                    }
                    else
                    {
                        _logger?.LogWarning($"Transaction is disabled for migration {migration.Version}");
                    }

                    _logger?.LogInformation($"{operationName} to {migration.Version} ({migration.Comment} for database \"{_dbProvider.DbName}\")...");

                    if (isUpgrade)
                    {
                        await migration.UpgradeAsync(transaction, token);

                        await _dbProvider.SaveAppliedMigrationVersionAsync(migration.Comment, migration.Version, token);
                    }
                    else
                    {
                        if (!(migration is IDowngradeMigration downgradableMigration))
                        {
                            throw new MigrationException(MigrationError.MigrationNotFound, $"Migration with version {migration.Version} doesn't support downgrade");
                        }

                        await downgradableMigration.DowngradeAsync(transaction, token);

                        await _dbProvider.DeleteAppliedMigrationVersionAsync(migration.Version, token);
                    }

                    // Commit transaction if all commands succeed, transaction will auto-rollback
                    // when disposed if either commands fails
                    transaction?.Commit();

                    _logger?.LogInformation($"{operationName} to {migration.Version} (database \"{_dbProvider.DbName}\") completed.");
                }
                catch (Exception e)
                {
                    throw new MigrationException(
                              MigrationError.MigratingError,
                              $"Error while executing {operationName.ToLower()} migration to {migration.Version} for database \"{_dbProvider.DbName}\": {e.Message}",
                              e);
                }
                finally
                {
                    transaction?.Dispose();
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Default realisation of <see cref="IDbMigrator"/>
        /// </summary>
        /// <param name="dbProvider">Provider for database</param>
        /// <param name="migrations">Main migrations for changing database</param>
        /// <param name="upgradePolicy">Policy for upgrading database</param>
        /// <param name="downgradePolicy">Policy for downgrading database</param>
        /// <param name="preMigrations">Migrations that will be executed before <paramref name="migrations"/></param>
        /// <param name="targetVersion">Desired version of database after migration. If <see langword="null"/> migrator will upgrade database to the most actual version</param>
        /// <param name="logger">Optional logger</param>
        public DbMigrator(
            IDbProvider dbProvider,
            ICollection <IMigration> migrations,
            MigrationPolicy upgradePolicy,
            MigrationPolicy downgradePolicy,
            ICollection <IMigration>?preMigrations = null,
            DbVersion?targetVersion = null,
            ILogger?logger          = null)
        {
            if (migrations == null)
            {
                throw new ArgumentNullException(nameof(migrations));
            }
            _dbProvider = dbProvider ?? throw new ArgumentNullException(nameof(dbProvider));
            _logger     = logger;

            var migrationMap = new Dictionary <DbVersion, IMigration>();

            foreach (var migration in migrations)
            {
                if (migrationMap.ContainsKey(migration.Version))
                {
                    throw new ArgumentException(
                              $"There is more than one migration with version {migration.Version}", nameof(migrations));
                }

                migrationMap.Add(migration.Version, migration);
            }

            _migrationMap = migrationMap;

            _upgradePolicy   = upgradePolicy;
            _downgradePolicy = downgradePolicy;
            _targetVersion   = targetVersion;

            _preMigrations = preMigrations ?? Array.Empty <IMigration>();
            var preMigrationCheckMap = new HashSet <DbVersion>();

            foreach (var migration in _preMigrations)
            {
                if (preMigrationCheckMap.Contains(migration.Version))
                {
                    throw new ArgumentException($"There is more than one pre-migration with version = {migration.Version}", nameof(preMigrations));
                }

                preMigrationCheckMap.Add(migration.Version);
            }

            if (targetVersion.HasValue && migrationMap.Values.Count > 0)
            {
                var migrationsMaxVersion = _migrationMap.Values.Max(x => x.Version);
                if (targetVersion > migrationsMaxVersion)
                {
                    throw new ArgumentException("Target version can't be greater than max available migration version", nameof(targetVersion));
                }

                if (_migrationMap.Values.All(x => x.Version != targetVersion))
                {
                    throw new ArgumentException($"No migrations were registered with desired target version (target version = {targetVersion})", nameof(targetVersion));
                }
            }
        }
Exemplo n.º 6
0
 /// <summary>
 /// Setup downgrade migration policy
 /// </summary>
 /// <param name="policy">Policy</param>
 /// <returns></returns>
 public MigratorBuilder UseDowngradeMigrationPolicy(MigrationPolicy policy)
 {
     _downgradePolicy = policy;
     return(this);
 }
Exemplo n.º 7
0
 /// <summary>
 /// Setup upgrade migration policy
 /// </summary>
 /// <param name="policy">Policy</param>
 /// <returns></returns>
 public MigratorBuilder UseUpgradeMigrationPolicy(MigrationPolicy policy)
 {
     _upgradePolicy = policy;
     return(this);
 }