Хранение имен модулей внутри карты в базе данных - PullRequest
0 голосов
/ 31 мая 2019

Я создаю службу уведомлений для приложения IOT, используя Elixir / Ecto / Phoenix. Датчик в этом приложении может иметь несколько значений, например

temperature: ["temp"],
accelerometer: ["ax", "ay", "az"]

Чтобы создать общую политику уведомлений, я должен сохранить имя модуля с датчиком, который будет реализовывать логику для обработки правила соответствия. Кроме того, поскольку каждый датчик может иметь несколько значений, связанных с ним accelerometer -> ax, ay, az, модуль может отличаться для разных значений.

  schema("acqdat_sensor_notifications") do
    field(:rule_values, :map)
    field(:alarm_status, :boolean, default: false)
    belongs_to(:sensor, Sensor, on_replace: :delete)

    timestamps()
  end

В столбце значений правил будут храниться данные в следующем формате, например для датчика акселерометра.

%{
  "ax" => %{ 
    module: "NotificationPolicyA", 
    module_preferences: {"prefA": valuea, "prefb": valueb}
  },
  "ay" => %{ 
    module: "NotificationPolicyB", 
    module_preferences: {"pref1": value1, "pref2": value2}
  },
}

Проблема здесь в сохранении имени модуля, который будет обрабатывать логику. Я не могу использовать библиотеку перечислений, такую ​​как ecto_enum, поскольку значения хранятся в карте jsonb, которая не является константой (здесь нельзя использовать встраивания). Оно постоянно меняется в зависимости от имени датчика и модуля, используемого для его обработки.

В настоящее время я занимаюсь этим с помощью карты

%{
  NotificationPolicyA: 0, 
  NotificationPolicyA: 1 
  .
  .
  .
}

, а затем сохранить целые числа в БД, чтобы при изменении имени модуля изменялась только карта.

"ax" => %{ 
    module: 0, 
    module_preferences: {"prefA": valuea, "prefb": valueb}
  }

Какой может быть альтернативный подход для обработки такого сценария с экто?

1 Ответ

1 голос
/ 31 мая 2019

Вы можете сохранить имя модуля в виде строки в базе данных, использовать String.to_existing_atom/1 для его преобразования и Kernel.apply/3 для запуска любой необходимой функции.

Пример:

iex(2)> apply(String.to_existing_atom("Elixir.MyApp.Version"), :run, [1])
0.29.1
...