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:
master
2026-02-23 15:30:50 +02:00
parent bd8fee6ed8
commit e746577380
1424 changed files with 81225 additions and 25251 deletions

View File

@@ -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)