fix(sql): bind string keys untyped on Postgres so integer key columns compare (#602 STAB-24)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 07:03:00 -04:00
parent 5a5c80ee57
commit 71881163df
8 changed files with 161 additions and 0 deletions
@@ -114,6 +114,63 @@ public sealed class PostgresReadTests
.ShouldBe(PostgresFixture.NewestStationOvenTemp);
}
// ---- integer key columns (STAB-24) ----
/// <summary>
/// A key-value tag whose key column is <c>integer</c> reads. Authored <c>keyValue</c> is text, and
/// Npgsql's default <c>text</c> bind has no <c>integer = text</c> operator — the read failed with a
/// provider error before <c>PostgresDialect.ConfigureParameter</c> sent string binds untyped.
/// </summary>
[Fact]
public async Task ReadAsync_realPostgres_integerKeyColumnComparesAgainstAuthoredText()
{
SkipUnlessLive();
await using var driver = await StartAsync(Tag("Sql/IntKey/Tag101", new JsonObject
{
["driver"] = "Sql",
["model"] = "KeyValue",
["table"] = PostgresFixture.Qualified("int_tag_values"),
["keyColumn"] = "tag_id",
["keyValue"] = "101",
["valueColumn"] = PostgresFixture.ValueColumn,
["timestampColumn"] = PostgresFixture.TimestampColumn,
}));
var snapshot = (await driver.ReadAsync(["Sql/IntKey/Tag101"], TestContext.Current.CancellationToken))
.ShouldHaveSingleItem();
SqlStatusCodes.IsGood(snapshot.StatusCode).ShouldBeTrue();
Convert.ToDouble(snapshot.Value, CultureInfo.InvariantCulture).ShouldBe(77.5);
}
/// <summary>A wide-row <c>whereColumn</c> selector over the <c>integer station_id</c> column reads the matching row.</summary>
[Fact]
public async Task ReadAsync_realPostgres_integerWhereColumnSelectsTheMatchingStation()
{
SkipUnlessLive();
await using var driver = await StartAsync(Tag("Sql/Station7/OvenTemp", new JsonObject
{
["driver"] = "Sql",
["model"] = "WideRow",
["table"] = PostgresFixture.Qualified(PostgresFixture.WideRowTable),
["columnName"] = "oven_temp",
["timestampColumn"] = PostgresFixture.TimestampColumn,
["rowSelector"] = new JsonObject
{
["whereColumn"] = "station_id",
["whereValue"] = "7",
},
}));
var snapshot = (await driver.ReadAsync(["Sql/Station7/OvenTemp"], TestContext.Current.CancellationToken))
.ShouldHaveSingleItem();
SqlStatusCodes.IsGood(snapshot.StatusCode).ShouldBeTrue();
Convert.ToDouble(snapshot.Value, CultureInfo.InvariantCulture).ShouldBe(180.5);
}
// ---- catalog case-folding (design §8.1 gate, against a real information_schema) ----
/// <summary>