using Npgsql; using Tiku.Application.Tenancy; using Tiku.Domain.Tenancy; namespace Tiku.Infrastructure.Tenancy; public sealed class TenantDirectory(NpgsqlDataSource dataSource) : ITenantDirectory { public Task FindByHostAsync( string host, CancellationToken cancellationToken = default) { const string sql = """ select t.id, t.slug, t.name, t.status, t.mode, d.host from tenant_domains d join tenants t on t.id = d.tenant_id where d.host = @lookup and d.status = 'active' and t.status = 'active' limit 1 """; return FindAsync(sql, host, cancellationToken); } public Task FindByCodeAsync( string tenantCode, CancellationToken cancellationToken = default) { const string sql = """ select t.id, t.slug, t.name, t.status, t.mode, null::text as host from tenants t where t.slug = @lookup and t.status = 'active' limit 1 """; return FindAsync(sql, tenantCode, cancellationToken); } private async Task FindAsync( string sql, string lookup, CancellationToken cancellationToken) { await using var command = dataSource.CreateCommand(sql); command.Parameters.AddWithValue("lookup", lookup); await using var reader = await command.ExecuteReaderAsync(cancellationToken); if (!await reader.ReadAsync(cancellationToken)) { return null; } return new TenantDirectoryEntry( reader.GetGuid(0), reader.GetString(1), reader.GetString(2), ParseEnum(reader.GetString(3)), ParseEnum(reader.GetString(4)), reader.IsDBNull(5) ? null : reader.GetString(5)); } private static TEnum ParseEnum(string value) where TEnum : struct, Enum { return Enum.Parse(value.Replace("_", string.Empty, StringComparison.Ordinal), true); } }