wip: doctor/cli/docs/api to vector db consolidation; api hardening for descriptions, tenant, and scopes; migrations and conversions of all DALs to EF v10
This commit is contained in:
@@ -104,7 +104,8 @@ public static class MigrationServiceExtensions
|
||||
string schemaName,
|
||||
string moduleName,
|
||||
Assembly migrationsAssembly,
|
||||
Func<TOptions, string> connectionStringSelector)
|
||||
Func<TOptions, string> connectionStringSelector,
|
||||
string? resourcePrefix = null)
|
||||
where TOptions : class
|
||||
{
|
||||
services.AddSingleton<IMigrationStatusService>(sp =>
|
||||
@@ -118,7 +119,8 @@ public static class MigrationServiceExtensions
|
||||
schemaName,
|
||||
moduleName,
|
||||
migrationsAssembly,
|
||||
logger);
|
||||
logger,
|
||||
resourcePrefix);
|
||||
});
|
||||
|
||||
return services;
|
||||
@@ -217,6 +219,13 @@ public sealed record MigrationStatus
|
||||
/// </summary>
|
||||
public sealed record PendingMigrationInfo(string Name, MigrationCategory Category);
|
||||
|
||||
/// <summary>
|
||||
/// Migration source descriptor (assembly + optional resource prefix).
|
||||
/// </summary>
|
||||
public sealed record MigrationAssemblySource(
|
||||
Assembly MigrationsAssembly,
|
||||
string? ResourcePrefix = null);
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of migration status service.
|
||||
/// </summary>
|
||||
@@ -225,7 +234,7 @@ public sealed class MigrationStatusService : IMigrationStatusService
|
||||
private readonly string _connectionString;
|
||||
private readonly string _schemaName;
|
||||
private readonly string _moduleName;
|
||||
private readonly Assembly _migrationsAssembly;
|
||||
private readonly IReadOnlyList<MigrationAssemblySource> _migrationSources;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public MigrationStatusService(
|
||||
@@ -233,12 +242,30 @@ public sealed class MigrationStatusService : IMigrationStatusService
|
||||
string schemaName,
|
||||
string moduleName,
|
||||
Assembly migrationsAssembly,
|
||||
ILogger logger,
|
||||
string? resourcePrefix = null)
|
||||
: this(
|
||||
connectionString,
|
||||
schemaName,
|
||||
moduleName,
|
||||
[new MigrationAssemblySource(migrationsAssembly, resourcePrefix)],
|
||||
logger)
|
||||
{
|
||||
}
|
||||
|
||||
public MigrationStatusService(
|
||||
string connectionString,
|
||||
string schemaName,
|
||||
string moduleName,
|
||||
IReadOnlyList<MigrationAssemblySource> migrationSources,
|
||||
ILogger logger)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
_schemaName = schemaName;
|
||||
_moduleName = moduleName;
|
||||
_migrationsAssembly = migrationsAssembly;
|
||||
_migrationSources = migrationSources is null || migrationSources.Count == 0
|
||||
? throw new ArgumentException("At least one migration source is required.", nameof(migrationSources))
|
||||
: migrationSources;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -338,27 +365,50 @@ public sealed class MigrationStatusService : IMigrationStatusService
|
||||
|
||||
private List<(string Name, MigrationCategory Category, string Checksum)> LoadMigrationsFromAssembly()
|
||||
{
|
||||
var migrations = new List<(string, MigrationCategory, string)>();
|
||||
var resourceNames = _migrationsAssembly.GetManifestResourceNames()
|
||||
.Where(name => name.EndsWith(".sql", StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(name => name);
|
||||
|
||||
foreach (var resourceName in resourceNames)
|
||||
var migrations = new Dictionary<string, (MigrationCategory Category, string Checksum)>(StringComparer.Ordinal);
|
||||
foreach (var source in _migrationSources)
|
||||
{
|
||||
using var stream = _migrationsAssembly.GetManifestResourceStream(resourceName);
|
||||
if (stream is null) continue;
|
||||
var resourceNames = source.MigrationsAssembly.GetManifestResourceNames()
|
||||
.Where(name => name.EndsWith(".sql", StringComparison.OrdinalIgnoreCase))
|
||||
.Where(name =>
|
||||
string.IsNullOrWhiteSpace(source.ResourcePrefix) ||
|
||||
name.Contains(source.ResourcePrefix, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderBy(name => name, StringComparer.Ordinal);
|
||||
|
||||
using var reader = new StreamReader(stream);
|
||||
var content = reader.ReadToEnd();
|
||||
foreach (var resourceName in resourceNames)
|
||||
{
|
||||
using var stream = source.MigrationsAssembly.GetManifestResourceStream(resourceName);
|
||||
if (stream is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var fileName = ExtractFileName(resourceName);
|
||||
var category = MigrationCategoryExtensions.GetCategory(fileName);
|
||||
var checksum = ComputeChecksum(content);
|
||||
using var reader = new StreamReader(stream);
|
||||
var content = reader.ReadToEnd();
|
||||
|
||||
migrations.Add((fileName, category, checksum));
|
||||
var fileName = ExtractFileName(resourceName);
|
||||
var category = MigrationCategoryExtensions.GetCategory(fileName);
|
||||
var checksum = ComputeChecksum(content);
|
||||
|
||||
if (migrations.TryGetValue(fileName, out var existing))
|
||||
{
|
||||
if (!string.Equals(existing.Checksum, checksum, StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Duplicate migration name '{fileName}' discovered across migration sources for module '{_moduleName}'.");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
migrations[fileName] = (category, checksum);
|
||||
}
|
||||
}
|
||||
|
||||
return migrations;
|
||||
return migrations
|
||||
.OrderBy(static pair => pair.Key, StringComparer.Ordinal)
|
||||
.Select(static pair => (pair.Key, pair.Value.Category, pair.Value.Checksum))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static string ExtractFileName(string resourceName)
|
||||
|
||||
Reference in New Issue
Block a user