1 using Microsoft.EntityFrameworkCore;
2 using Microsoft.EntityFrameworkCore.Infrastructure;
3 using Microsoft.EntityFrameworkCore.Migrations;
4 using Microsoft.Extensions.DependencyInjection;
5 using Microsoft.Extensions.Logging;
11 using System.Threading.Tasks;
21 #pragma warning disable CA1506 // TODO: Decomplexify 27 public DbSet<User> Users {
get;
set; }
32 public DbSet<Instance> Instances {
get;
set; }
37 public DbSet<CompileJob> CompileJobs {
get;
set; }
42 public DbSet<RevisionInformation> RevisionInformations {
get;
set; }
52 public DbSet<ChatBot> ChatBots {
get;
set; }
67 public DbSet<InstanceUser> InstanceUsers {
get;
set; }
72 public DbSet<ChatChannel> ChatChannels {
get;
set; }
77 public DbSet<Job> Jobs {
get;
set; }
82 public DbSet<ReattachInformation> ReattachInformations {
get;
set; }
87 public DbSet<TestMerge> TestMerges {
get;
set; }
92 public DbSet<RevInfoTestMerge> RevInfoTestMerges {
get;
set; }
97 protected virtual DeleteBehavior RevInfoCompileJobDeleteBehavior => DeleteBehavior.ClientNoAction;
200 public static Action<DbContextOptionsBuilder, DatabaseConfiguration> GetConfigureAction<TDatabaseContext>()
205 var configureFunction = typeof(TDatabaseContext).GetMethod(
207 BindingFlags.Public | BindingFlags.Static);
209 if (configureFunction == null)
210 throw new InvalidOperationException($
"Context type {typeof(TDatabaseContext).FullName} missing static {ConfigureMethodName} function!");
212 return (optionsBuilder, config) => configureFunction.Invoke(null,
new object[] { optionsBuilder, config });
238 if (modelBuilder == null)
239 throw new ArgumentNullException(nameof(modelBuilder));
241 base.OnModelCreating(modelBuilder);
243 var userModel = modelBuilder.Entity<
User>();
244 userModel.HasIndex(x => x.CanonicalName).IsUnique();
245 userModel.HasIndex(x => x.SystemIdentifier).IsUnique();
246 userModel.HasMany(x => x.TestMerges).WithOne(x => x.MergedBy).OnDelete(DeleteBehavior.Restrict);
248 modelBuilder.Entity<
InstanceUser>().HasIndex(x =>
new { x.UserId, x.InstanceId }).IsUnique();
251 revInfo.HasMany(x => x.ActiveTestMerges).WithOne(x => x.RevisionInformation).OnDelete(DeleteBehavior.Cascade);
252 revInfo.HasOne(x => x.PrimaryTestMerge).WithOne(x => x.PrimaryRevisionInformation).OnDelete(DeleteBehavior.Cascade);
253 revInfo.HasIndex(x =>
new { x.InstanceId, x.CommitSha }).IsUnique();
262 revInfo.HasMany(x => x.CompileJobs).WithOne(x => x.RevisionInformation).OnDelete(RevInfoCompileJobDeleteBehavior);
265 modelBuilder.Entity<
TestMerge>().HasMany(x => x.RevisonInformations).WithOne(x => x.TestMerge).OnDelete(DeleteBehavior.ClientNoAction);
267 var compileJob = modelBuilder.Entity<
CompileJob>();
268 compileJob.HasIndex(x => x.DirectoryName);
269 compileJob.HasOne(x => x.Job).WithOne().OnDelete(DeleteBehavior.Cascade);
271 modelBuilder.Entity<
ReattachInformation>().HasOne(x => x.CompileJob).WithMany().OnDelete(DeleteBehavior.Cascade);
273 var chatChannel = modelBuilder.Entity<
ChatChannel>();
274 chatChannel.HasIndex(x =>
new { x.ChatSettingsId, x.IrcChannel }).IsUnique();
275 chatChannel.HasIndex(x =>
new { x.ChatSettingsId, x.DiscordChannelId }).IsUnique();
276 chatChannel.HasOne(x => x.ChatSettings).WithMany(x => x.Channels).HasForeignKey(x => x.ChatSettingsId).OnDelete(DeleteBehavior.Cascade);
278 modelBuilder.Entity<
ChatBot>().HasIndex(x =>
new { x.InstanceId, x.Name }).IsUnique();
280 var instanceModel = modelBuilder.Entity<
Instance>();
281 instanceModel.HasIndex(x => x.Path).IsUnique();
282 instanceModel.HasMany(x => x.ChatSettings).WithOne(x => x.Instance).OnDelete(DeleteBehavior.Cascade);
283 instanceModel.HasOne(x => x.DreamDaemonSettings).WithOne(x => x.Instance).OnDelete(DeleteBehavior.Cascade);
284 instanceModel.HasOne(x => x.DreamMakerSettings).WithOne(x => x.Instance).OnDelete(DeleteBehavior.Cascade);
285 instanceModel.HasOne(x => x.RepositorySettings).WithOne(x => x.Instance).OnDelete(DeleteBehavior.Cascade);
286 instanceModel.HasMany(x => x.RevisionInformations).WithOne(x => x.Instance).OnDelete(DeleteBehavior.Cascade);
287 instanceModel.HasMany(x => x.InstanceUsers).WithOne(x => x.Instance).OnDelete(DeleteBehavior.Cascade);
288 instanceModel.HasMany(x => x.Jobs).WithOne(x => x.Instance).OnDelete(DeleteBehavior.Cascade);
292 public Task Save(CancellationToken cancellationToken) => SaveChangesAsync(cancellationToken);
295 public Task Drop(CancellationToken cancellationToken) => Database.EnsureDeletedAsync(cancellationToken);
298 public async Task<bool>
Migrate(ILogger<DatabaseContext> logger, CancellationToken cancellationToken)
301 throw new ArgumentNullException(nameof(logger));
302 var migrations = await Database.GetAppliedMigrationsAsync(cancellationToken).ConfigureAwait(
false);
303 var wasEmpty = !migrations.Any();
305 if (wasEmpty || (await Database.GetPendingMigrationsAsync(cancellationToken).ConfigureAwait(
false)).Any())
307 logger.LogInformation(
"Migrating database...");
308 await Database.MigrateAsync(cancellationToken).ConfigureAwait(
false);
311 logger.LogDebug(
"No migrations to apply");
313 wasEmpty |= (await Users.AsQueryable().CountAsync(cancellationToken).ConfigureAwait(
false)) == 0;
320 ILogger<DatabaseContext> logger,
323 CancellationToken cancellationToken)
326 throw new ArgumentNullException(nameof(logger));
328 throw new ArgumentNullException(nameof(version));
329 if (version <
new Version(4, 0))
330 throw new ArgumentOutOfRangeException(nameof(version), version,
"Not a valid V4 version!");
333 string targetMigration = null;
335 if (currentDatabaseType ==
DatabaseType.PostgresSql && version <
new Version(4, 3, 0))
336 throw new NotSupportedException(
"Cannot migrate below version 4.3.0 with PostgresSql!");
338 if (version <
new Version(4, 1, 0))
339 throw new NotSupportedException(
"Cannot migrate below version 4.1.0!");
341 if(version <
new Version(4, 4, 0))
342 switch (currentDatabaseType)
356 throw new ArgumentException($
"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType));
359 if (version <
new Version(4, 2, 0))
362 if (targetMigration == null)
364 logger.LogDebug(
"No down migration required.");
368 string migrationSubstitution;
369 switch (currentDatabaseType)
373 migrationSubstitution = null;
377 migrationSubstitution =
"MY{0}";
380 migrationSubstitution =
"SL{0}";
383 migrationSubstitution =
"PG{0}";
386 throw new InvalidOperationException($
"Invalid DatabaseType: {currentDatabaseType}");
389 if (migrationSubstitution != null)
390 targetMigration = String.Format(CultureInfo.InvariantCulture, migrationSubstitution, targetMigration.Substring(2));
393 var dbServiceProvider = ((IInfrastructure<IServiceProvider>)Database).Instance;
394 var migrator = dbServiceProvider.GetRequiredService<IMigrator>();
396 logger.LogInformation(
"Migrating down to version {0}. Target: {1}", version, targetMigration);
399 await migrator.MigrateAsync(targetMigration, cancellationToken).ConfigureAwait(
false);
403 logger.LogCritical(
"Failed to migrate! Exception: {0}", e);
IDatabaseCollection< RevisionInformation > RevisionInformations
The RevisionInformations in the IDatabaseContext
IDatabaseCollection< InstanceUser > InstanceUsers
The InstanceUsers in the IDatabaseContext
DatabaseContext(DbContextOptions dbContextOptions)
Construct a DatabaseContext
IDatabaseCollection< ChatChannel > ChatChannels
The ChatChannel in the IDatabaseContext
Use server authentication
Fix the CompileJob/RevisionInformation foreign key for MySQL.
readonly IDatabaseCollection< ChatChannel > chatChannelsCollection
Backing field for IDatabaseContext.ChatChannels.
Fix cascading data deletes for Models.Instances on MSSQL.
IDatabaseCollection< CompileJob > CompileJobs
The CompileJobs in the IDatabaseContext
Backend abstract implementation of IDatabaseContext
IDatabaseCollection< Instance > Instances
The Instances in the IDatabaseContext
Rebuild of the schema for SQLite.
IDatabaseCollection< ChatBot > ChatBots
The ChatBots in the IDatabaseContext
static void ConfigureWith(DbContextOptionsBuilder options, DatabaseConfiguration databaseConfiguration)
Configure the SqlServerDatabaseContext.
IDatabaseCollection< RepositorySettings > RepositorySettings
The Models.RepositorySettings in the IDatabaseContext
readonly IDatabaseCollection< Instance > instancesCollection
Backing field for IDatabaseContext.Instances.
readonly IDatabaseCollection< DreamMakerSettings > dreamMakerSettingsCollection
Backing field for IDatabaseContext.DreamMakerSettings.
IDatabaseCollection< DreamMakerSettings > DreamMakerSettings
The Models.DreamMakerSettings in the IDatabaseContext
readonly IDatabaseCollection< User > usersCollection
Backing field for IDatabaseContext.Users.
readonly IDatabaseCollection< RevisionInformation > revisionInformationsCollection
Backing field for IDatabaseContext.RevisionInformations.
Represents an Api.Models.Instance in the database
Create initial schema for PostgresSQL.
readonly IDatabaseCollection< CompileJob > compileJobsCollection
Backing field for IDatabaseContext.CompileJobs.
DatabaseType
Type of database to user
readonly IDatabaseCollection< InstanceUser > instanceUsersCollection
Backing field for IDatabaseContext.InstanceUsers.
override void OnModelCreating(ModelBuilder modelBuilder)
readonly IDatabaseCollection< DreamDaemonSettings > dreamDaemonSettingsCollection
Backing field for IDatabaseContext.DreamDaemonSettings.
readonly IDatabaseCollection< ChatBot > chatBotsCollection
Backing field for IDatabaseContext.ChatBots.
readonly IDatabaseCollection< RepositorySettings > repositorySettingsCollection
Backing field for IDatabaseContext.RepositorySettings.
IDatabaseCollection< DreamDaemonSettings > DreamDaemonSettings
The Models.DreamDaemonSettings in the IDatabaseContext
IDatabaseCollection< ReattachInformation > ReattachInformations
The DbSet<TEntity> for ReattachInformations
IDatabaseCollection< Job > Jobs
The Jobs in the IDatabaseContext
DatabaseContext for Sqlserver
readonly IDatabaseCollection< ReattachInformation > reattachInformationsCollection
Backing field for IDatabaseContext.ReattachInformations.
IDatabaseCollection< User > Users
The Users in the IDatabaseContext
readonly IDatabaseCollection< Job > jobsCollection
Backing field for IDatabaseContext.Jobs.
Removes various defunct columns for MSSQL.
async Task SchemaDowngradeForServerVersion(ILogger< DatabaseContext > logger, Version version, DatabaseType currentDatabaseType, CancellationToken cancellationToken)
Attempt to downgrade the schema to the migration used for a given server version ...
async Task< bool > Migrate(ILogger< DatabaseContext > logger, CancellationToken cancellationToken)
Creates and migrates the IDatabaseContext