From e152c741e567764bafed7da25d72be3c76dbbd57 Mon Sep 17 00:00:00 2001 From: Jason Staack Date: Sat, 21 Mar 2026 23:59:20 -0500 Subject: [PATCH] fix: replace all :: type casts with CAST() in SQLAlchemy text() calls SQLAlchemy's text() interprets :name::type as two named parameters. Fixes syntax errors in link discovery, signal history, and SNMP profile CRUD that caused 500 errors at runtime. Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/app/routers/snmp_profiles.py | 4 ++-- backend/app/services/link_discovery_subscriber.py | 6 +++--- backend/app/services/signal_history_service.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/app/routers/snmp_profiles.py b/backend/app/routers/snmp_profiles.py index 173e860..de81c2d 100644 --- a/backend/app/routers/snmp_profiles.py +++ b/backend/app/routers/snmp_profiles.py @@ -163,7 +163,7 @@ async def create_profile( category, profile_data, is_system) VALUES (:tenant_id, :name, :description, :sys_object_id, :vendor, - :category, :profile_data::jsonb, FALSE) + :category, CAST(:profile_data AS jsonb), FALSE) RETURNING id, tenant_id, name, description, sys_object_id, vendor, category, is_system, created_at, updated_at """), @@ -234,7 +234,7 @@ async def update_profile( for field, value in fields.items(): if field == "profile_data" and value is not None: - set_clauses.append(f"{field} = :{field}::jsonb") + set_clauses.append(f"{field} = CAST(:{field} AS jsonb)") updates[field] = json.dumps(value) else: set_clauses.append(f"{field} = :{field}") diff --git a/backend/app/services/link_discovery_subscriber.py b/backend/app/services/link_discovery_subscriber.py index 9ce0f44..ca08bb2 100644 --- a/backend/app/services/link_discovery_subscriber.py +++ b/backend/app/services/link_discovery_subscriber.py @@ -106,8 +106,8 @@ async def on_wireless_registration_for_links(msg) -> None: (gen_random_uuid(), :ap_device_id, :cpe_device_id, :tenant_id, :interface, :client_mac, :signal_strength, :tx_ccq, :tx_rate, :rx_rate, - CASE WHEN :signal_strength::int IS NULL THEN 'active' - WHEN :signal_strength::int < :degraded_threshold THEN 'degraded' + CASE WHEN CAST(:signal_strength AS int) IS NULL THEN 'active' + WHEN CAST(:signal_strength AS int) < :degraded_threshold THEN 'degraded' ELSE 'active' END, 0, NOW(), NOW(), NOW()) ON CONFLICT (ap_device_id, cpe_device_id) DO UPDATE SET @@ -152,7 +152,7 @@ async def on_wireless_registration_for_links(msg) -> None: WHERE ap_device_id = :ap_device_id AND tenant_id = :tenant_id AND cpe_device_id NOT IN ( - SELECT unnest(:seen_cpe_ids::uuid[]) + SELECT unnest(CAST(:seen_cpe_ids AS uuid[])) ) AND state NOT IN ('down', 'stale') """), diff --git a/backend/app/services/signal_history_service.py b/backend/app/services/signal_history_service.py index 79053a8..115270a 100644 --- a/backend/app/services/signal_history_service.py +++ b/backend/app/services/signal_history_service.py @@ -51,7 +51,7 @@ async def get_signal_history( WHERE wr.mac_address = :mac_address AND wr.device_id = :device_id AND wr.tenant_id = :tenant_id - AND wr.time > now() - :lookback::interval + AND wr.time > now() - CAST(:lookback AS interval) AND wr.signal_strength IS NOT NULL GROUP BY bucket ORDER BY bucket