using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MeterVault.Infrastructure.Persistence.Migrations
{
///
public partial class BindUnboundMqttSourcesToSoleBroker : Migration
{
///
protected override void Up(MigrationBuilder migrationBuilder)
{
// MQTT routing now honours meter_source.endpoint_id (SDD §6.1): a source is served only
// by the broker it is bound to. Previously an unbound source was subscribed on every
// broker and matched on topic alone, so unbound sources that work today would silently
// go quiet after this deploy.
//
// Backfill them onto the single broker only when exactly one exists — then the old
// "any broker" behaviour and the new "its broker" behaviour are the same thing, so the
// rewrite is provably lossless. With zero brokers there is nothing to bind to; with two
// or more the old behaviour was already ambiguous and a guess could route a meter's
// data to the wrong broker, so those are left for the operator to resolve in the UI.
//
// Enums persist as their C# names (HasConversion), hence 'Mqtt'/'MqttBroker'.
// HomeAssistant sources are deliberately excluded: the HA workers have always required
// endpoint_id, so an unbound HA source is already inert and binding it here would
// activate ingestion the operator never had running.
migrationBuilder.Sql("""
UPDATE meter_source AS s
SET endpoint_id = sole.id
FROM (SELECT id FROM ingestion_endpoint WHERE type = 'MqttBroker') AS sole
WHERE s.endpoint_id IS NULL
AND s.source_type IN ('Mqtt', 'Tasmota')
AND (SELECT count(*) FROM ingestion_endpoint WHERE type = 'MqttBroker') = 1;
""");
}
///
protected override void Down(MigrationBuilder migrationBuilder)
{
// Intentionally empty. The rows this bound are indistinguishable from ones the operator
// bound by hand, so clearing endpoint_id on the way down would discard real
// configuration. Leaving the binding in place is harmless under the old routing, which
// ignored endpoint_id entirely.
}
}
}