forked from bittercoder/Migrator.NET
-
-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathMigrationLoader.cs
More file actions
157 lines (134 loc) · 5.28 KB
/
Copy pathMigrationLoader.cs
File metadata and controls
157 lines (134 loc) · 5.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using DotNetProjects.Migrator.Framework;
using DotNetProjects.Migrator.Providers;
namespace DotNetProjects.Migrator;
/// <summary>
/// Handles inspecting code to find all of the Migrations in assemblies and reading
/// other metadata such as the last revision, etc.
/// </summary>
public class MigrationLoader
{
private readonly List<Type> _migrationsTypes = new List<Type>();
private readonly ITransformationProvider _provider;
public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace)
{
_provider = provider;
AddMigrations(migrationAssembly);
if (trace) TraceMigrations();
}
public MigrationLoader(ITransformationProvider provider, bool trace, params Type[] migrationTypes)
{
_provider = provider;
_migrationsTypes.AddRange(migrationTypes);
if (trace) TraceMigrations();
}
private void TraceMigrations()
{
_provider.Logger.Trace("Loaded migrations:");
foreach (var type in _migrationsTypes)
_provider.Logger.Trace("{0} {1}", (type.GetCustomAttribute<MigrationAttribute>()?.Version.ToString() ?? "aux").PadLeft(5), StringUtils.ToHumanName(type.Name));
}
/// <summary>
/// Returns registered migration <see cref="System.Type">types</see>.
/// </summary>
public virtual List<Type> MigrationsTypes
{
get { return _migrationsTypes; }
}
/// <summary>
/// Returns the last version of the migrations.
/// </summary>
public virtual long LastVersion
{
get
{
if (_migrationsTypes.Count == 0)
{
return 0;
}
return SelectedTypes.Select(GetMigrationVersion).DefaultIfEmpty(0).Max();
}
}
public Func<Type, IMigration> Activator { get; set; }
public IEnumerable<Type> SelectedTypes => _migrationsTypes.Where(t =>
t.GetCustomAttribute<MigrationAttribute>() != null && InScope(t.GetCustomAttribute<MigrationAttribute>().Scope));
internal bool InScope(string scope) => scope == null || _provider is not IMigrationHistory history || scope == history.Scope;
internal IEnumerable<Type> AuxiliaryTypes => _migrationsTypes.Where(t => t.GetCustomAttribute<MigrationAttribute>() == null);
public virtual void AddMigrations(Assembly migrationAssembly)
{
if (migrationAssembly != null)
{
_migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly));
}
}
/// <summary>
/// Check for duplicated version in migrations.
/// </summary>
/// <exception cref="CheckForDuplicatedVersion">CheckForDuplicatedVersion</exception>
public virtual void CheckForDuplicatedVersion()
{
var versions = new HashSet<long>();
foreach (var t in SelectedTypes)
{
var version = GetMigrationVersion(t);
if (!versions.Add(version))
{
throw new DuplicatedVersionException(version);
}
}
}
/// <summary>
/// Collect migrations in one <c>Assembly</c>.
/// </summary>
/// <param name="asm">The <c>Assembly</c> to browse.</param>
/// <returns>The migrations collection</returns>
public static List<Type> GetMigrationTypes(Assembly asm)
{
var migrations = new List<Type>();
foreach (var t in asm.GetExportedTypes())
{
if (t.IsAbstract || !typeof(IMigration).IsAssignableFrom(t)) continue;
var versioned = t.GetCustomAttribute<MigrationAttribute>();
if (versioned != null ? !versioned.Ignore :
t.GetCustomAttribute<ProfileAttribute>() != null || t.GetCustomAttribute<MaintenanceAttribute>() != null)
migrations.Add(t);
}
migrations = migrations.OrderBy(t => t.GetCustomAttribute<MigrationAttribute>()?.Version ?? 0).ThenBy(t => t.FullName, StringComparer.Ordinal).ToList();
return migrations;
}
/// <summary>
/// Returns the version of the migration
/// <see cref="MigrationAttribute">MigrationAttribute</see>.
/// </summary>
/// <param name="t">Migration type.</param>
/// <returns>Version number sepcified in the attribute</returns>
public static long GetMigrationVersion(Type t)
{
var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute));
return attrib?.Version ?? throw new ArgumentException($"{t.FullName} has no Migration attribute.");
}
public List<long> GetAvailableMigrations()
{
return SelectedTypes.Select(GetMigrationVersion).OrderBy(v => v).ToList();
}
public virtual IMigration GetMigration(long version)
{
foreach (var t in SelectedTypes)
{
if (GetMigrationVersion(t) == version)
{
var migration = CreateInstance(t);
migration.Database = _provider;
return migration;
}
}
return null;
}
public virtual IMigration CreateInstance(Type migrationType)
{
return Activator != null ? Activator(migrationType) ?? throw new MigrationException("Migration activator returned null.") : (IMigration)System.Activator.CreateInstance(migrationType);
}
}