fix(external-system-gateway): resolve ExternalSystemGateway-011 — name-keyed repository lookups replace fetch-all-then-filter on the call hot path

This commit is contained in:
Joseph Doherty
2026-05-17 00:02:45 -04:00
parent 1e2e7d2e7c
commit a55502254e
10 changed files with 448 additions and 131 deletions

View File

@@ -53,6 +53,31 @@ public class SiteExternalSystemRepository : IExternalSystemRepository
return all.FirstOrDefault(e => e.Id == id);
}
/// <summary>
/// ExternalSystemGateway-011: genuine name-keyed lookup. The <c>external_systems</c>
/// table has <c>name</c> as its PRIMARY KEY, so this is a single indexed-row fetch
/// rather than the previous fetch-all-then-filter.
/// </summary>
public async Task<ExternalSystemDefinition?> GetExternalSystemByNameAsync(
string name, CancellationToken cancellationToken = default)
{
await using var connection = CreateConnection();
await connection.OpenAsync(cancellationToken);
await using var command = connection.CreateCommand();
command.CommandText = @"
SELECT name, endpoint_url, auth_type, auth_configuration
FROM external_systems
WHERE name = @name";
command.Parameters.AddWithValue("@name", name);
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
if (!await reader.ReadAsync(cancellationToken))
return null;
return MapExternalSystem(reader);
}
// ── ExternalSystemMethod (read) ──
public async Task<IReadOnlyList<ExternalSystemMethod>> GetMethodsByExternalSystemIdAsync(
@@ -80,6 +105,23 @@ public class SiteExternalSystemRepository : IExternalSystemRepository
return ParseMethodDefinitions(json, externalSystemId);
}
/// <summary>
/// ExternalSystemGateway-011: name-keyed method lookup. The site store keeps a
/// system's methods in a single JSON column, so this fetches that one row and
/// matches the named method in memory. The parent system is resolved via
/// <see cref="GetMethodsByExternalSystemIdAsync"/>, which already performs a
/// single keyed read of the <c>method_definitions</c> column — this is no more
/// I/O than the gateway's previous fetch-all-methods-then-filter call, and on
/// the SQL-backed Central repository it is a genuine indexed query.
/// </summary>
public async Task<ExternalSystemMethod?> GetMethodByNameAsync(
int externalSystemId, string methodName, CancellationToken cancellationToken = default)
{
var methods = await GetMethodsByExternalSystemIdAsync(externalSystemId, cancellationToken);
return methods.FirstOrDefault(
m => m.Name.Equals(methodName, StringComparison.OrdinalIgnoreCase));
}
public async Task<ExternalSystemMethod?> GetExternalSystemMethodByIdAsync(
int id, CancellationToken cancellationToken = default)
{
@@ -134,6 +176,38 @@ public class SiteExternalSystemRepository : IExternalSystemRepository
return all.FirstOrDefault(d => d.Id == id);
}
/// <summary>
/// ExternalSystemGateway-011: genuine name-keyed lookup. The
/// <c>database_connections</c> table has <c>name</c> as its PRIMARY KEY, so this
/// is a single indexed-row fetch rather than fetch-all-then-filter.
/// </summary>
public async Task<DatabaseConnectionDefinition?> GetDatabaseConnectionByNameAsync(
string name, CancellationToken cancellationToken = default)
{
await using var connection = CreateConnection();
await connection.OpenAsync(cancellationToken);
await using var command = connection.CreateCommand();
command.CommandText = @"
SELECT name, connection_string, max_retries, retry_delay_ms
FROM database_connections
WHERE name = @name";
command.Parameters.AddWithValue("@name", name);
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
if (!await reader.ReadAsync(cancellationToken))
return null;
return new DatabaseConnectionDefinition(
name: reader.GetString(0),
connectionString: reader.GetString(1))
{
Id = GenerateSyntheticId(reader.GetString(0)),
MaxRetries = reader.GetInt32(2),
RetryDelay = TimeSpan.FromMilliseconds(reader.GetInt64(3))
};
}
// ── Write operations (not supported on site) ──
public Task AddExternalSystemAsync(ExternalSystemDefinition definition, CancellationToken cancellationToken = default)