From 7b1d25e28630fad7ef54e53a977d69e05fe2924f Mon Sep 17 00:00:00 2001 From: l5y <220195275+l5yth@users.noreply.github.com> Date: Sat, 28 Mar 2026 21:21:13 +0100 Subject: [PATCH] fix upsert clearing node coordinates bug (#654) --- .../application/data_processing.rb | 11 ++++-- web/spec/app_spec.rb | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/web/lib/potato_mesh/application/data_processing.rb b/web/lib/potato_mesh/application/data_processing.rb index 5b61f66..630971d 100644 --- a/web/lib/potato_mesh/application/data_processing.rb +++ b/web/lib/potato_mesh/application/data_processing.rb @@ -357,9 +357,14 @@ module PotatoMesh is_favorite=excluded.is_favorite, hops_away=excluded.hops_away, snr=excluded.snr, last_heard=excluded.last_heard, first_heard=COALESCE(nodes.first_heard, excluded.first_heard, excluded.last_heard), battery_level=excluded.battery_level, voltage=excluded.voltage, channel_utilization=excluded.channel_utilization, - air_util_tx=excluded.air_util_tx, uptime_seconds=excluded.uptime_seconds, position_time=excluded.position_time, - location_source=excluded.location_source, precision_bits=excluded.precision_bits, latitude=excluded.latitude, longitude=excluded.longitude, - altitude=excluded.altitude, lora_freq=excluded.lora_freq, modem_preset=excluded.modem_preset + air_util_tx=excluded.air_util_tx, uptime_seconds=excluded.uptime_seconds, + position_time=COALESCE(excluded.position_time, nodes.position_time), + location_source=COALESCE(excluded.location_source, nodes.location_source), + precision_bits=COALESCE(excluded.precision_bits, nodes.precision_bits), + latitude=COALESCE(excluded.latitude, nodes.latitude), + longitude=COALESCE(excluded.longitude, nodes.longitude), + altitude=COALESCE(excluded.altitude, nodes.altitude), + lora_freq=excluded.lora_freq, modem_preset=excluded.modem_preset WHERE COALESCE(excluded.last_heard,0) >= COALESCE(nodes.last_heard,0) SQL end diff --git a/web/spec/app_spec.rb b/web/spec/app_spec.rb index 5aecd7f..7a682d8 100644 --- a/web/spec/app_spec.rb +++ b/web/spec/app_spec.rb @@ -2781,6 +2781,42 @@ RSpec.describe "Potato Mesh Sinatra app" do end end + it "preserves existing coordinates when a subsequent upsert has no position data" do + node_id = "!f7e74be6" + first_heard = reference_time.to_i - 3600 + + with_db do |db| + db.execute( + "INSERT INTO nodes(node_id, last_heard, first_heard, latitude, longitude, altitude, position_time) VALUES (?,?,?,?,?,?,?)", + [node_id, first_heard, first_heard, 53.8673152, 27.5283968, 271, first_heard], + ) + end + + nodeinfo_payload = { + node_id => { + "user" => { "shortName" => "MUTE", "longName" => "ClientMute", "hwModel" => "HELTEC_MESH_POCKET", "role" => "CLIENT_MUTE" }, + "lastHeard" => reference_time.to_i, + }, + } + + post "/api/nodes", nodeinfo_payload.to_json, auth_headers + + expect(last_response).to be_ok + + with_db(readonly: true) do |db| + db.results_as_hash = true + row = db.get_first_row( + "SELECT latitude, longitude, altitude, position_time FROM nodes WHERE node_id = ?", + [node_id], + ) + + expect(row["latitude"]).to be_within(1e-6).of(53.8673152) + expect(row["longitude"]).to be_within(1e-6).of(27.5283968) + expect(row["altitude"]).to be_within(0.01).of(271) + expect(row["position_time"]).to eq(first_heard) + end + end + it "returns 400 when more than 1000 nodes are provided" do payload = (0..1000).each_with_object({}) do |i, acc| acc["node-#{i}"] = {}