refactor(bootstrap): add seed loader + extractor scaffolding
This commit is contained in:
0
SVSim.Bootstrap/Data/seeds/.gitkeep
Normal file
0
SVSim.Bootstrap/Data/seeds/.gitkeep
Normal file
42
SVSim.Bootstrap/Importers/SeedLoader.cs
Normal file
42
SVSim.Bootstrap/Importers/SeedLoader.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace SVSim.Bootstrap.Importers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a JSON seed file under <c>SVSim.Bootstrap/Data/seeds/</c>. Replaces ImporterBase.LoadCapture.
|
||||||
|
/// Files are produced by extractors in <c>data_dumps/extract/</c>; the bootstrap project does not
|
||||||
|
/// transform wire formats. Missing files are non-fatal (returns empty/null) — caller decides.
|
||||||
|
/// </summary>
|
||||||
|
public static class SeedLoader
|
||||||
|
{
|
||||||
|
private static readonly JsonSerializerOptions Options = new()
|
||||||
|
{
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
|
NumberHandling = JsonNumberHandling.AllowReadingFromString,
|
||||||
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||||
|
AllowTrailingCommas = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static List<T> LoadList<T>(string path)
|
||||||
|
{
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[SeedLoader] Missing seed file: {path}");
|
||||||
|
return new List<T>();
|
||||||
|
}
|
||||||
|
using var fs = File.OpenRead(path);
|
||||||
|
return JsonSerializer.Deserialize<List<T>>(fs, Options) ?? new List<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T? LoadObject<T>(string path) where T : class
|
||||||
|
{
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[SeedLoader] Missing seed file: {path}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
using var fs = File.OpenRead(path);
|
||||||
|
return JsonSerializer.Deserialize<T>(fs, Options);
|
||||||
|
}
|
||||||
|
}
|
||||||
0
SVSim.Bootstrap/Models/Seed/.gitkeep
Normal file
0
SVSim.Bootstrap/Models/Seed/.gitkeep
Normal file
@@ -27,6 +27,9 @@
|
|||||||
<Content Include="Data\story\*.json">
|
<Content Include="Data\story\*.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<None Update="Data\seeds\**\*.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
39
SVSim.UnitTests/Importers/SeedLoaderTests.cs
Normal file
39
SVSim.UnitTests/Importers/SeedLoaderTests.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using SVSim.Bootstrap.Importers;
|
||||||
|
|
||||||
|
namespace SVSim.UnitTests.Importers;
|
||||||
|
|
||||||
|
public class SeedLoaderTests
|
||||||
|
{
|
||||||
|
private sealed record Row(int Id, string Name);
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void LoadList_returns_empty_when_file_missing()
|
||||||
|
{
|
||||||
|
string path = Path.Combine(Path.GetTempPath(), $"missing-{Guid.NewGuid()}.json");
|
||||||
|
var rows = SeedLoader.LoadList<Row>(path);
|
||||||
|
Assert.That(rows, Is.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void LoadList_deserializes_snake_case_array()
|
||||||
|
{
|
||||||
|
string path = Path.Combine(Path.GetTempPath(), $"seed-{Guid.NewGuid()}.json");
|
||||||
|
File.WriteAllText(path, "[{\"id\":1,\"name\":\"a\"},{\"id\":2,\"name\":\"b\"}]");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var rows = SeedLoader.LoadList<Row>(path);
|
||||||
|
Assert.That(rows, Has.Count.EqualTo(2));
|
||||||
|
Assert.That(rows[0].Id, Is.EqualTo(1));
|
||||||
|
Assert.That(rows[1].Name, Is.EqualTo("b"));
|
||||||
|
}
|
||||||
|
finally { File.Delete(path); }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void LoadObject_returns_null_when_file_missing()
|
||||||
|
{
|
||||||
|
string path = Path.Combine(Path.GetTempPath(), $"missing-{Guid.NewGuid()}.json");
|
||||||
|
var row = SeedLoader.LoadObject<Row>(path);
|
||||||
|
Assert.That(row, Is.Null);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user