mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-14 17:54:42 +00:00
Add sqlite load into Database.Seed
This commit is contained in:
@@ -111,8 +111,9 @@ if(NOT BIERGARTEN_MOCK_ONLY)
|
|||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(llama-cpp)
|
FetchContent_MakeAvailable(llama-cpp)
|
||||||
endif()
|
endif()
|
||||||
|
if (NOT APPLE)
|
||||||
find_package(OpenMP REQUIRED)
|
find_package(OpenMP REQUIRED)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# spdlog
|
# spdlog
|
||||||
@@ -249,9 +250,10 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
|||||||
includes
|
includes
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||||
$<$<NOT:$<BOOL:${BIERGARTEN_MOCK_ONLY}>>:llama>
|
$<$<NOT:$<BOOL:${BIERGARTEN_MOCK_ONLY}>>:llama>
|
||||||
$<$<NOT:$<BOOL:${BIERGARTEN_MOCK_ONLY}>>:OpenMP::OpenMP_CXX>
|
$<TARGET_NAME_IF_EXISTS:OpenMP::OpenMP_CXX>
|
||||||
boost::di
|
boost::di
|
||||||
Boost::json
|
Boost::json
|
||||||
Boost::program_options
|
Boost::program_options
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ void XegerGenerator::Visit(const Alternation& node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void XegerGenerator::Visit(const Repeat& node) {
|
void XegerGenerator::Visit(const Repeat& node) {
|
||||||
const int lo = node.min;
|
const unsigned int low = node.min;
|
||||||
const int hi = (node.max < 0) ? node.min + unbounded_cap_ : node.max;
|
const unsigned int high = node.max.value_or(node.min + unbounded_cap_);
|
||||||
std::uniform_int_distribution<int> dist(lo, hi);
|
std::uniform_int_distribution<unsigned int> dist(low, high);
|
||||||
const int count = dist(rng_);
|
const unsigned int count = dist(rng_);
|
||||||
for (int i = 0; i < count; ++i) {
|
for (unsigned int i = 0; i < count; ++i) {
|
||||||
node.child->Accept(*this);
|
node.child->Accept(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<!--
|
<!--
|
||||||
remove this override once microsoft ships official fix to vulnerability
|
remove this override once microsoft ships official fix to vulnerability
|
||||||
https://github.com/advisories/GHSA-2m69-gcr7-jv3q
|
https:
|
||||||
-->
|
-->
|
||||||
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" Version="3.50.3" />
|
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" Version="3.50.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -24,4 +24,10 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Domain\Domain.Entities\Domain.Entities.csproj" />
|
<ProjectReference Include="..\..\Domain\Domain.Entities\Domain.Entities.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<!-- Pipeline-generated seed data, copied to the output directory so it can be opened via
|
||||||
|
ConnectionStrings.SqliteConnectionString at runtime. -->
|
||||||
|
<None Include="SeedData\seed.sqlite" CopyToOutputDirectory="PreserveNewest" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,19 +1,9 @@
|
|||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
namespace Database.Seed;
|
namespace Database.Seed.DatabaseHelpers;
|
||||||
|
|
||||||
public class ConnectionStrings
|
public class ConnectionStrings
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Builds a SQL Server connection string from the <c>DB_SERVER</c>, <c>DB_NAME</c>,
|
|
||||||
/// <c>DB_USER</c>, <c>DB_PASSWORD</c>, and <c>DB_TRUST_SERVER_CERTIFICATE</c>
|
|
||||||
/// environment variables.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A fully built SQL Server connection string.</returns>
|
|
||||||
/// <exception cref="InvalidOperationException">
|
|
||||||
/// Thrown when <c>DB_SERVER</c>, <c>DB_NAME</c>, <c>DB_USER</c>, or <c>DB_PASSWORD</c>
|
|
||||||
/// is not set.
|
|
||||||
/// </exception>
|
|
||||||
private static string GetSqlServerConnectionString()
|
private static string GetSqlServerConnectionString()
|
||||||
{
|
{
|
||||||
string server =
|
string server =
|
||||||
@@ -48,7 +38,6 @@ public class ConnectionStrings
|
|||||||
return builder.ConnectionString;
|
return builder.ConnectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static string SqlServerConnectionString => GetSqlServerConnectionString();
|
public static string SqlServerConnectionString => GetSqlServerConnectionString();
|
||||||
public static string SqliteConnectionString => "Data Source=seed.sqlite";
|
public static string SqliteConnectionString => "Data Source=SeedData/seed.sqlite";
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record BreweryAddress
|
||||||
|
{
|
||||||
|
public required City City { get; init; }
|
||||||
|
|
||||||
|
public required string PostalCode { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record BreweryRecord
|
||||||
|
{
|
||||||
|
public required BreweryAddress Address { get; init; }
|
||||||
|
|
||||||
|
public required BreweryResult Brewery { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record BreweryResult
|
||||||
|
{
|
||||||
|
public required string NameEn { get; init; }
|
||||||
|
|
||||||
|
public required string DescriptionEn { get; init; }
|
||||||
|
|
||||||
|
public required string NameLocal { get; init; }
|
||||||
|
|
||||||
|
public required string DescriptionLocal { get; init; }
|
||||||
|
}
|
||||||
18
web/backend/Database/Database.Seed/PipelineData/City.cs
Normal file
18
web/backend/Database/Database.Seed/PipelineData/City.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record City
|
||||||
|
{
|
||||||
|
public required string CityName { get; init; }
|
||||||
|
|
||||||
|
public required string StateProvince { get; init; }
|
||||||
|
|
||||||
|
public required string Iso31662 { get; init; }
|
||||||
|
|
||||||
|
public required string Country { get; init; }
|
||||||
|
|
||||||
|
public required string Iso31661 { get; init; }
|
||||||
|
|
||||||
|
public IReadOnlyList<string> LocalLanguages { get; init; } = [];
|
||||||
|
|
||||||
|
public required PostalCodeSpec PostalCode { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record PostalCodeSpec
|
||||||
|
{
|
||||||
|
public required string CountryFormatRegex { get; init; }
|
||||||
|
|
||||||
|
public IReadOnlyList<string> CityRegexes { get; init; } = [];
|
||||||
|
|
||||||
|
public IReadOnlyList<string> Examples { get; init; } = [];
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record UserAddress
|
||||||
|
{
|
||||||
|
public required City City { get; init; }
|
||||||
|
|
||||||
|
public required string PostalCode { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record UserRecord
|
||||||
|
{
|
||||||
|
public required UserAddress Address { get; init; }
|
||||||
|
|
||||||
|
public required UserResult User { get; init; }
|
||||||
|
|
||||||
|
public required string Email { get; init; }
|
||||||
|
|
||||||
|
public required string DateOfBirth { get; init; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace Database.Seed.PipelineData;
|
||||||
|
|
||||||
|
public sealed record UserResult
|
||||||
|
{
|
||||||
|
public required string FirstName { get; init; }
|
||||||
|
|
||||||
|
public required string LastName { get; init; }
|
||||||
|
|
||||||
|
public required string Gender { get; init; }
|
||||||
|
|
||||||
|
public required string Username { get; init; }
|
||||||
|
|
||||||
|
public required string Bio { get; init; }
|
||||||
|
|
||||||
|
public required float ActivityWeight { get; init; }
|
||||||
|
}
|
||||||
53
web/backend/Database/Database.Seed/Program.cs
Normal file
53
web/backend/Database/Database.Seed/Program.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using Database.Seed.DatabaseHelpers;
|
||||||
|
using Database.Seed.PipelineData;
|
||||||
|
using Database.Seed.Sqlite;
|
||||||
|
using Microsoft.Data.Sqlite;
|
||||||
|
|
||||||
|
namespace Database.Seed;
|
||||||
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static int Main()
|
||||||
|
{
|
||||||
|
IReadOnlyList<BreweryRecord> breweries;
|
||||||
|
IReadOnlyList<UserRecord> users;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PipelineSeedDataReader reader = new(ConnectionStrings.SqliteConnectionString);
|
||||||
|
breweries = reader.ReadBreweryRecords();
|
||||||
|
users = reader.ReadUserRecords();
|
||||||
|
}
|
||||||
|
catch (SqliteException ex)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine($"Error opening database connection: {ex.Message}");
|
||||||
|
Console.ResetColor();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
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})");
|
||||||
|
}
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine($"Loaded {users.Count} users.");
|
||||||
|
Console.ResetColor();
|
||||||
|
|
||||||
|
for (int i = 0; i < users.Count; i++)
|
||||||
|
{
|
||||||
|
UserRecord user = users[i];
|
||||||
|
Console.WriteLine($"{i + 1}:\t{user.User.FirstName} {user.User.LastName}\t ({user.Email})");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
web/backend/Database/Database.Seed/SeedData/seed.sqlite
Normal file
BIN
web/backend/Database/Database.Seed/SeedData/seed.sqlite
Normal file
Binary file not shown.
@@ -0,0 +1,135 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Database.Seed.PipelineData;
|
||||||
|
using Microsoft.Data.Sqlite;
|
||||||
|
|
||||||
|
namespace Database.Seed.Sqlite;
|
||||||
|
|
||||||
|
public sealed class PipelineSeedDataReader
|
||||||
|
{
|
||||||
|
private readonly string _connectionString;
|
||||||
|
|
||||||
|
public PipelineSeedDataReader(string connectionString)
|
||||||
|
{
|
||||||
|
_connectionString = connectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<BreweryRecord> ReadBreweryRecords()
|
||||||
|
{
|
||||||
|
using SqliteConnection connection = new(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
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;
|
||||||
|
""";
|
||||||
|
|
||||||
|
using SqliteCommand command = new(sql, connection);
|
||||||
|
using SqliteDataReader reader = command.ExecuteReader();
|
||||||
|
|
||||||
|
List<BreweryRecord> records = [];
|
||||||
|
while (reader.Read())
|
||||||
|
records.Add(
|
||||||
|
new BreweryRecord
|
||||||
|
{
|
||||||
|
Brewery = new BreweryResult
|
||||||
|
{
|
||||||
|
NameEn = reader.GetString(0),
|
||||||
|
DescriptionEn = reader.GetString(1),
|
||||||
|
NameLocal = reader.GetString(2),
|
||||||
|
DescriptionLocal = reader.GetString(3),
|
||||||
|
},
|
||||||
|
Address = new BreweryAddress
|
||||||
|
{
|
||||||
|
City = cities[reader.GetInt64(4)],
|
||||||
|
PostalCode = reader.GetString(5),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<UserRecord> ReadUserRecords()
|
||||||
|
{
|
||||||
|
using SqliteConnection connection = new(_connectionString);
|
||||||
|
connection.Open();
|
||||||
|
|
||||||
|
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;
|
||||||
|
""";
|
||||||
|
|
||||||
|
using SqliteCommand command = new(sql, connection);
|
||||||
|
using SqliteDataReader reader = command.ExecuteReader();
|
||||||
|
|
||||||
|
List<UserRecord> records = [];
|
||||||
|
while (reader.Read())
|
||||||
|
records.Add(
|
||||||
|
new UserRecord
|
||||||
|
{
|
||||||
|
User = new UserResult
|
||||||
|
{
|
||||||
|
FirstName = reader.GetString(0),
|
||||||
|
LastName = reader.GetString(1),
|
||||||
|
Gender = reader.GetString(2),
|
||||||
|
Username = reader.GetString(3),
|
||||||
|
Bio = reader.GetString(4),
|
||||||
|
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),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
""";
|
||||||
|
|
||||||
|
using SqliteCommand command = new(sql, connection);
|
||||||
|
using SqliteDataReader reader = command.ExecuteReader();
|
||||||
|
|
||||||
|
Dictionary<long, City> cities = [];
|
||||||
|
while (reader.Read())
|
||||||
|
cities[reader.GetInt64(0)] = new City
|
||||||
|
{
|
||||||
|
CityName = reader.GetString(1),
|
||||||
|
StateProvince = reader.GetString(2),
|
||||||
|
Iso31662 = reader.GetString(3),
|
||||||
|
Country = reader.GetString(4),
|
||||||
|
Iso31661 = reader.GetString(5),
|
||||||
|
LocalLanguages = DeserializeStringArray(reader.GetString(6)),
|
||||||
|
PostalCode = new PostalCodeSpec
|
||||||
|
{
|
||||||
|
CountryFormatRegex = reader.GetString(7),
|
||||||
|
CityRegexes = DeserializeStringArray(reader.GetString(8)),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return cities;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<string> DeserializeStringArray(string json) =>
|
||||||
|
JsonSerializer.Deserialize<List<string>>(json) ?? [];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user