This commit is contained in:
Aaron Po
2026-08-04 06:22:19 -04:00
parent f665df578c
commit 37667db2f6
19 changed files with 117 additions and 109 deletions

View File

@@ -180,8 +180,7 @@ public static class Program
!bool.TryParse(
Environment.GetEnvironmentVariable("DB_TRUST_SERVER_CERTIFICATE"),
out bool parsedTrust
)
|| parsedTrust;
) || parsedTrust;
bool clearDatabase = string.Equals(
Environment.GetEnvironmentVariable("CLEAR_DATABASE"),
@@ -204,7 +203,7 @@ public static class Program
UserID = user,
Password = password,
Encrypt = true,
TrustServerCertificate = trustServerCertificate
TrustServerCertificate = trustServerCertificate,
}.ConnectionString;
}
@@ -214,4 +213,4 @@ public static class Program
$"The {variableName} environment variable is not set."
);
}
}
}

View File

@@ -21,8 +21,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Domain\Domain.Entities\Domain.Entities.csproj" />
<ProjectReference
Include="..\..\Infrastructure\Infrastructure.Sql\Infrastructure.Sql.csproj" />
<ProjectReference Include="..\..\Infrastructure\Infrastructure.Sql\Infrastructure.Sql.csproj" />
<ProjectReference Include="..\..\Features\Features.Breweries\Features.Breweries.csproj" />
<ProjectReference Include="..\..\Features\Features.Auth\Features.Auth.csproj" />
</ItemGroup>
@@ -30,7 +29,9 @@
<ItemGroup>
<!-- Pipeline-generated seed data, copied to the output directory so it can be opened via
ConnectionStrings.SqliteConnectionString at runtime. -->
<None CopyToOutputDirectory="PreserveNewest"
Include="SeedData\biergarten_seed_2026-07-20T05-46-02.993511Z.sqlite" />
<None
CopyToOutputDirectory="PreserveNewest"
Include="SeedData\biergarten_seed_2026-07-20T05-46-02.993511Z.sqlite"
/>
</ItemGroup>
</Project>

View File

@@ -9,7 +9,8 @@ namespace Database.Seed.DatabaseHelpers;
public class ConnectionStrings
{
public static string SqlServerConnectionString => GetSqlServerConnectionString();
public static string SqliteConnectionString => "Data Source=SeedData/biergarten_seed_2026-07-20T05-46-02.993511Z.sqlite";
public static string SqliteConnectionString =>
"Data Source=SeedData/biergarten_seed_2026-07-20T05-46-02.993511Z.sqlite";
private static string GetSqlServerConnectionString()
{
@@ -39,7 +40,7 @@ public class ConnectionStrings
UserID = user,
Password = password,
TrustServerCertificate = bool.Parse(trustServerCertificate),
Encrypt = true
Encrypt = true,
};
return builder.ConnectionString;

View File

@@ -5,4 +5,4 @@ public sealed record BreweryAddress
public required City City { get; init; }
public required string PostalCode { get; init; }
}
}

View File

@@ -5,4 +5,4 @@ public sealed record BreweryRecord
public required BreweryAddress Address { get; init; }
public required BreweryResult Brewery { get; init; }
}
}

View File

@@ -9,4 +9,4 @@ public sealed record BreweryResult
public required string NameLocal { get; init; }
public required string DescriptionLocal { get; init; }
}
}

View File

@@ -15,4 +15,4 @@ public sealed record City
public IReadOnlyList<string> LocalLanguages { get; init; } = [];
public required PostalCodeSpec PostalCode { get; init; }
}
}

View File

@@ -7,4 +7,4 @@ public sealed record PostalCodeSpec
public IReadOnlyList<string> CityRegexes { get; init; } = [];
public IReadOnlyList<string> Examples { get; init; } = [];
}
}

View File

@@ -5,4 +5,4 @@ public sealed record UserAddress
public required City City { get; init; }
public required string PostalCode { get; init; }
}
}

View File

@@ -9,4 +9,4 @@ public sealed record UserRecord
public required string Email { get; init; }
public required string DateOfBirth { get; init; }
}
}

View File

@@ -13,4 +13,4 @@ public sealed record UserResult
public required string Bio { get; init; }
public required float ActivityWeight { get; init; }
}
}

View File

@@ -1,23 +1,20 @@
using Database.Seed.DatabaseHelpers;
using Database.Seed.PipelineData;
using Database.Seed.Sqlite;
using Domain.Entities;
using Features.Auth.DependencyInjection;
using Features.Auth.Dtos;
using Features.Auth.Repository;
using Features.Breweries.DependencyInjection;
using Features.Breweries.Repository;
using idunno.Password;
using Infrastructure.PasswordHashing;
using Infrastructure.Sql;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using idunno.Password;
using Infrastructure.PasswordHashing;
using Domain.Entities;
async static Task<int> main()
static async Task<int> main()
{
IReadOnlyList<BreweryRecord> breweries;
IReadOnlyList<UserRecord> users;
@@ -61,16 +58,15 @@ async static Task<int> main()
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(
$"Loaded {breweries.Count} breweries."
);
Console.WriteLine($"Loaded {breweries.Count} breweries.");
Console.ResetColor();
for (int i = 0; i < breweries.Count; i++)
{
BreweryRecord brewery = breweries[i];
Console.WriteLine(
$"{i + 1}:\t{brewery.Brewery.NameEn}\t({brewery.Address.City.CityName}, {brewery.Address.City.Country})");
$"{i + 1}:\t{brewery.Brewery.NameEn}\t({brewery.Address.City.CityName}, {brewery.Address.City.Country})"
);
}
Console.ForegroundColor = ConsoleColor.Green;
@@ -87,7 +83,11 @@ async static Task<int> main()
// Generate a password that is 64 characters long with 10 digits, 10 symbols,
// allowing upper and lower case letters, disallowing repeat characters.
string generatedPassword = PasswordGenerator.Generate(length: 64, numberOfDigits: 10, numberOfSymbols: 10);
string generatedPassword = PasswordGenerator.Generate(
length: 64,
numberOfDigits: 10,
numberOfSymbols: 10
);
string hashedPassword = passwordInfrastructure.Hash(generatedPassword);
UserRegistrationDto registrationDto = new(
@@ -102,7 +102,9 @@ async static Task<int> main()
try
{
UserAccount createdUser = await authRepository.RegisterUserAsync(registrationDto);
Console.WriteLine($"Created user: {createdUser.Username} ({createdUser.UserAccountId})");
Console.WriteLine(
$"Created user: {createdUser.Username} ({createdUser.UserAccountId})"
);
}
catch (Exception ex)
{
@@ -110,11 +112,9 @@ async static Task<int> main()
Console.WriteLine($"Error creating user {username}: {ex.Message}");
Console.ResetColor();
}
}
return 0;
}
return await main();

View File

@@ -25,11 +25,11 @@ public sealed class PipelineSeedDataReader
IReadOnlyDictionary<long, City> cities = ReadCities(connection);
const string sql = """
SELECT b.name_en, b.description_en, b.name_local, b.description_local,
ba.city_id, ba.postal_code
FROM breweries b
JOIN brewery_addresses ba ON ba.brewery_id = b.id;
""";
SELECT b.name_en, b.description_en, b.name_local, b.description_local,
ba.city_id, ba.postal_code
FROM breweries b
JOIN brewery_addresses ba ON ba.brewery_id = b.id;
""";
using SqliteCommand command = new(sql, connection);
using SqliteDataReader reader = command.ExecuteReader();
@@ -44,13 +44,13 @@ public sealed class PipelineSeedDataReader
NameEn = reader.GetString(0),
DescriptionEn = reader.GetString(1),
NameLocal = reader.GetString(2),
DescriptionLocal = reader.GetString(3)
DescriptionLocal = reader.GetString(3),
},
Address = new BreweryAddress
{
City = cities[reader.GetInt64(4)],
PostalCode = reader.GetString(5)
}
PostalCode = reader.GetString(5),
},
}
);
@@ -65,12 +65,12 @@ public sealed class PipelineSeedDataReader
IReadOnlyDictionary<long, City> cities = ReadCities(connection);
const string sql = """
SELECT u.first_name, u.last_name, u.gender, u.username, u.bio,
u.activity_weight, u.email, u.date_of_birth,
ua.city_id, ua.postal_code
FROM users u
JOIN user_addresses ua ON ua.user_id = u.id;
""";
SELECT u.first_name, u.last_name, u.gender, u.username, u.bio,
u.activity_weight, u.email, u.date_of_birth,
ua.city_id, ua.postal_code
FROM users u
JOIN user_addresses ua ON ua.user_id = u.id;
""";
using SqliteCommand command = new(sql, connection);
using SqliteDataReader reader = command.ExecuteReader();
@@ -87,15 +87,15 @@ public sealed class PipelineSeedDataReader
Gender = reader.GetString(2),
Username = reader.GetString(3),
Bio = reader.GetString(4),
ActivityWeight = (float)reader.GetDouble(5)
ActivityWeight = (float)reader.GetDouble(5),
},
Email = reader.GetString(6),
DateOfBirth = reader.GetString(7),
Address = new UserAddress
{
City = cities[reader.GetInt64(8)],
PostalCode = reader.GetString(9)
}
PostalCode = reader.GetString(9),
},
}
);
@@ -105,18 +105,18 @@ public sealed class PipelineSeedDataReader
private static IReadOnlyDictionary<long, City> ReadCities(SqliteConnection connection)
{
const string sql = """
SELECT
id,
city,
state_province,
iso3166_2,
country,
iso3166_1,
local_languages_json,
postal_code_country_format_regex,
postal_code_city_regex_json
FROM cities;
""";
SELECT
id,
city,
state_province,
iso3166_2,
country,
iso3166_1,
local_languages_json,
postal_code_country_format_regex,
postal_code_city_regex_json
FROM cities;
""";
using SqliteCommand command = new(sql, connection);
using SqliteDataReader reader = command.ExecuteReader();
@@ -144,14 +144,13 @@ public sealed class PipelineSeedDataReader
PostalCode = new PostalCodeSpec
{
CountryFormatRegex = reader.GetString(countryFormatRegexBindIndex),
CityRegexes = DeserializeStringArray(reader.GetString(cityRegexesBindIndex))
}
CityRegexes = DeserializeStringArray(reader.GetString(cityRegexesBindIndex)),
},
};
return cities;
}
private static IReadOnlyList<string> DeserializeStringArray(string json)
{
return JsonSerializer.Deserialize<List<string>>(json) ?? [];

View File

@@ -1,18 +1,17 @@
namespace Database.Seed;
public interface IExportDatabase
{
void SeedLocations(IEnumerable<Location> locations);
void SeedUsers(IEnumerable<User> users);
void SeedLocations(IEnumerable<Location> locations);
void SeedUsers(IEnumerable<User> users);
void SeedBreweries(IEnumerable<Brewery> breweries);
void SeedBreweries(IEnumerable<Brewery> breweries);
}
public interface IImportDatabase
{
IEnumerable<Location> GetLocations();
IEnumerable<User> GetUsers();
IEnumerable<Location> GetLocations();
IEnumerable<User> GetUsers();
IEnumerable<Brewery> GetBreweries();
IEnumerable<Brewery> GetBreweries();
}