Foxnouns.NET/migrators/NetImporter/NetImporter.cs
sam d982342ab8
refactor: pass DbContextOptions into context directly
turns out efcore doesn't like it when we create a new options instance
(which includes a new data source *and* a new logger factory)
every single time we create a context. this commit extracts
OnConfiguring into static methods which are called when the context is
added to the service collection and when it's manually created for
migrations and the importer.
2024-10-30 15:35:23 +01:00

89 lines
2.8 KiB
C#

using Foxnouns.Backend;
using Foxnouns.Backend.Database;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using NodaTime;
using NodaTime.Serialization.JsonNet;
using Serilog;
using Serilog.Events;
namespace NetImporter;
internal static class NetImporter
{
public static async Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override(
"Microsoft.EntityFrameworkCore.Database.Command",
LogEventLevel.Information
)
.WriteTo.Console()
.CreateLogger();
switch (args.Length)
{
case < 2:
Console.WriteLine("Not enough arguments. Usage: <type> <file>");
return;
case > 2:
Console.WriteLine("Too many arguments. Usage: <type> <file>");
return;
}
switch (args[0].ToLowerInvariant())
{
case "users":
await Users.ImportUsers(args[1]);
break;
default:
Console.WriteLine("Invalid type. Valid types are: users");
break;
}
}
internal static async Task<DatabaseContext> GetContextAsync()
{
var connString = Environment.GetEnvironmentVariable("DATABASE");
if (connString == null)
throw new Exception("$DATABASE not set, must be an ADO.NET connection string");
var loggerFactory = new LoggerFactory().AddSerilog(Log.Logger);
var config = new Config { Database = new Config.DatabaseConfig { Url = connString } };
var dataSource = DatabaseContext.BuildDataSource(config);
var options = DatabaseContext
.BuildOptions(new DbContextOptionsBuilder(), dataSource, loggerFactory)
.Options;
var db = new DatabaseContext(options);
if ((await db.Database.GetPendingMigrationsAsync()).Any())
{
Log.Fatal("Database needs to be migrated first");
}
return db;
}
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy(),
},
}.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
internal static Input<T> ReadFromFile<T>(string path)
{
var data = File.ReadAllText(path);
return JsonConvert.DeserializeObject<Input<T>>(data, Settings)
?? throw new Exception("Invalid input file");
}
}
internal record Input<T>(List<T> Output, List<string> Skipped);