improve profile import

This commit is contained in:
Graham McIntire 2026-01-18 11:46:56 -06:00
parent dab3e29025
commit 5b1b9a08c7
No known key found for this signature in database
5 changed files with 135 additions and 6 deletions

View file

@ -319,12 +319,15 @@ defmodule Towerops.DeviceProfiles.Importer do
defp import_sensors_of_class(profile_id, sensor_class, sensors) do
Enum.each(sensors, fn sensor ->
# Skip sensors without a valid OID (required for SNMP polling)
if sensor["oid"] || sensor["num_oid"] do
# Check for both nil and empty string
has_valid_oid = present?(sensor["oid"]) || present?(sensor["num_oid"])
if has_valid_oid do
attrs = %{
device_profile_id: profile_id,
sensor_class: sensor_class,
oid: sensor["oid"],
num_oid: sensor["num_oid"],
oid: nilify_blank(sensor["oid"]),
num_oid: nilify_blank(sensor["num_oid"]),
index: to_string(sensor["index"] || ""),
descr: sensor["descr"],
divisor: calculate_divisor(sensor["precision"]),
@ -406,4 +409,15 @@ defmodule Towerops.DeviceProfiles.Importer do
|> Enum.reject(fn {_k, v} -> is_nil(v) end)
|> Map.new()
end
# Check if a value is present (not nil and not empty string)
defp present?(nil), do: false
defp present?(""), do: false
defp present?(_), do: true
# Convert OID values, preserving all data types since the field is now JSONB
# Only convert empty strings to nil
defp nilify_blank(nil), do: nil
defp nilify_blank(""), do: nil
defp nilify_blank(value), do: value
end

View file

@ -11,14 +11,15 @@ defmodule Towerops.DeviceProfiles.SensorDefinition do
alias Towerops.DeviceProfiles.DeviceProfile
alias Towerops.DeviceProfiles.SensorState
alias Towerops.EctoTypes.JsonAny
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "profile_sensor_definitions" do
field :sensor_class, :string
field :oid, :string
field :num_oid, :string
field :oid, JsonAny
field :num_oid, JsonAny
field :index, :string
field :descr, :string
field :divisor, :integer, default: 1
@ -33,7 +34,7 @@ defmodule Towerops.DeviceProfiles.SensorDefinition do
field :skip_value_lt, :float
field :skip_value_gt, :float
field :user_func, :string
field :entPhysicalIndex, :string
field :entPhysicalIndex, JsonAny
field :group, :string
field :options, :map

View file

@ -0,0 +1,39 @@
defmodule Towerops.EctoTypes.JsonAny do
@moduledoc """
Custom Ecto type for JSONB columns that can store any JSON-encodable value.
Unlike the built-in :map type which only accepts maps, this type accepts:
- strings
- numbers (integer, float)
- booleans
- nil
- lists
- maps
All values are stored as JSONB in the database.
"""
use Ecto.Type
def type, do: :jsonb
# Cast accepts any JSON-encodable value
def cast(nil), do: {:ok, nil}
def cast(value) when is_binary(value), do: {:ok, value}
def cast(value) when is_number(value), do: {:ok, value}
def cast(value) when is_boolean(value), do: {:ok, value}
def cast(value) when is_list(value), do: {:ok, value}
def cast(value) when is_map(value), do: {:ok, value}
def cast(_), do: :error
# Load from database - return as-is
def load(value), do: {:ok, value}
# Dump to database - return as-is, Postgres will handle JSON encoding
def dump(nil), do: {:ok, nil}
def dump(value) when is_binary(value), do: {:ok, value}
def dump(value) when is_number(value), do: {:ok, value}
def dump(value) when is_boolean(value), do: {:ok, value}
def dump(value) when is_list(value), do: {:ok, value}
def dump(value) when is_map(value), do: {:ok, value}
def dump(_), do: :error
end

View file

@ -0,0 +1,49 @@
defmodule Towerops.Repo.Migrations.ChangeSensorOidFieldsToJsonb do
use Ecto.Migration
def up do
# Convert oid column from VARCHAR to JSONB
# Existing string values will be stored as JSON strings
execute """
ALTER TABLE profile_sensor_definitions
ALTER COLUMN oid TYPE jsonb
USING CASE
WHEN oid IS NULL THEN NULL
ELSE to_jsonb(oid)
END
"""
# Convert num_oid column from VARCHAR to JSONB
execute """
ALTER TABLE profile_sensor_definitions
ALTER COLUMN num_oid TYPE jsonb
USING CASE
WHEN num_oid IS NULL THEN NULL
ELSE to_jsonb(num_oid)
END
"""
end
def down do
# Convert back to VARCHAR(255), extracting string values from JSONB
execute """
ALTER TABLE profile_sensor_definitions
ALTER COLUMN oid TYPE varchar(255)
USING CASE
WHEN oid IS NULL THEN NULL
WHEN jsonb_typeof(oid) = 'string' THEN oid #>> '{}'
ELSE oid::text
END
"""
execute """
ALTER TABLE profile_sensor_definitions
ALTER COLUMN num_oid TYPE varchar(255)
USING CASE
WHEN num_oid IS NULL THEN NULL
WHEN jsonb_typeof(num_oid) = 'string' THEN num_oid #>> '{}'
ELSE num_oid::text
END
"""
end
end

View file

@ -0,0 +1,26 @@
defmodule Towerops.Repo.Migrations.ChangeEntPhysicalIndexToJsonb do
use Ecto.Migration
def up do
execute """
ALTER TABLE profile_sensor_definitions
ALTER COLUMN "entPhysicalIndex" TYPE jsonb
USING CASE
WHEN "entPhysicalIndex" IS NULL THEN NULL
ELSE to_jsonb("entPhysicalIndex")
END
"""
end
def down do
execute """
ALTER TABLE profile_sensor_definitions
ALTER COLUMN "entPhysicalIndex" TYPE varchar(255)
USING CASE
WHEN "entPhysicalIndex" IS NULL THEN NULL
WHEN jsonb_typeof("entPhysicalIndex") = 'string' THEN "entPhysicalIndex" #>> '{}'
ELSE "entPhysicalIndex"::text
END
"""
end
end