67 lines
3.0 KiB
C#
67 lines
3.0 KiB
C#
using MongoDB.Bson;
|
|
using MongoDB.Driver;
|
|
using QuestionsApi.Models;
|
|
|
|
namespace QuestionsApi.Services;
|
|
|
|
public static class QuestionAttemptCycleMigrationCommand
|
|
{
|
|
public const string Confirmation = "MIGRATE_ATTEMPT_CYCLES";
|
|
public const string LegacyIndexName = "QuestionExternalId_1_UserId_1";
|
|
public const string CycleIndexName = "uq_question_user_cycle";
|
|
|
|
public static async Task<int> RunAsync(
|
|
IConfiguration configuration, string[] args, TextWriter output)
|
|
{
|
|
var apply = args.Contains("--apply", StringComparer.Ordinal);
|
|
var confirmation = Option(args, "--confirm");
|
|
var mongo = new MongoDatabaseProvider(configuration);
|
|
var attempts = mongo.Database.GetCollection<QuestionAttempt>("QuestionAttempts");
|
|
var missingFilter = new BsonDocumentFilterDefinition<QuestionAttempt>(
|
|
new BsonDocument(nameof(QuestionAttempt.BankCycle),
|
|
new BsonDocument("$exists", false)));
|
|
var missing = await attempts.CountDocumentsAsync(missingFilter);
|
|
var indexes = (await attempts.Indexes.ListAsync()).ToList();
|
|
var names = indexes.Select(value => value["name"].AsString).ToHashSet(StringComparer.Ordinal);
|
|
|
|
await output.WriteLineAsync(
|
|
$"QuestionAttempts missing BankCycle: {missing}; legacy index: {names.Contains(LegacyIndexName)}; cycle index: {names.Contains(CycleIndexName)}.");
|
|
if (!apply)
|
|
{
|
|
await output.WriteLineAsync(
|
|
$"Dry run only. Re-run with --apply --confirm {Confirmation}.");
|
|
return 0;
|
|
}
|
|
if (confirmation != Confirmation)
|
|
{
|
|
await output.WriteLineAsync($"Refusing migration: --confirm {Confirmation} is required.");
|
|
return 2;
|
|
}
|
|
|
|
if (missing > 0)
|
|
await attempts.UpdateManyAsync(
|
|
missingFilter,
|
|
Builders<QuestionAttempt>.Update.Set(value => value.BankCycle, 0));
|
|
if (!names.Contains(CycleIndexName))
|
|
await attempts.Indexes.CreateOneAsync(new CreateIndexModel<QuestionAttempt>(
|
|
Builders<QuestionAttempt>.IndexKeys
|
|
.Ascending(value => value.QuestionExternalId)
|
|
.Ascending(value => value.UserId)
|
|
.Ascending(value => value.BankCycle),
|
|
new CreateIndexOptions { Unique = true, Name = CycleIndexName }));
|
|
if (names.Contains(LegacyIndexName))
|
|
await attempts.Indexes.DropOneAsync(LegacyIndexName);
|
|
|
|
var remaining = await attempts.CountDocumentsAsync(missingFilter);
|
|
await output.WriteLineAsync(
|
|
$"Migration complete. Backfilled {missing}; missing BankCycle: {remaining}; dropped legacy index: {names.Contains(LegacyIndexName)}.");
|
|
return remaining == 0 ? 0 : 1;
|
|
}
|
|
|
|
private static string Option(string[] args, string name)
|
|
{
|
|
var index = Array.IndexOf(args, name);
|
|
return index >= 0 && index + 1 < args.Length ? args[index + 1] : "";
|
|
}
|
|
}
|