Как проверить nil/null в Lua cjson Redis?

У меня есть сценарий lua с блоком кода, как показано ниже:

local call_data     = cjson.decode(ARGV[1])
local other_data    = cjson.decode(ARGV[2])
local data          = {}
local next          = next
local populate_data = function(source)
  if next(source) == nil then
    return
  end

  for property,value in pairs(source) do
    redis.call('HSET', KEYS[2], property, value)
  end
end
populate_data(call_data)
populate_data(other_data)

Когда я пытаюсь запустить скрипт со следующей командой KEYS и ARGV как: -

redis-cli --eval dialed.lua "inflight_stats:18" "calls:AC443d7a8111a96ba8074f54a71f0521ce:CA1ec49703eee1959471c71506f43bb42e:dialed" , "{\"from\":\"+18035224181\",\"to\":\"+919943413333\",\"sid\":\"CA1ec49703eee1959471c71506f43bb42e\",\"status\":\"queued\",\"direction\":\"outbound-api\",\"date_created\":null,\"account_sid\":\"AC443d8a8111a96ba8074f54a71f0521ce\"}" "{\"phone\":\"919943413333\",\"campaign_id\":18,\"caller_session_sid\":\"CA828b163153bf5cc301ef5285e38925f9\"}" 0

Ошибка :-

(error) ERR Error running script (call to f_08dcc69ee8baa0200e0cf552948ab4bc338c9978): @user_script:11: @user_script: 11: Lua redis() command arguments must be strings or integers 

person Jaswinder    schedule 19.10.2018    source источник
comment
Вы можете использовать: ./redis-cli --ldb --eval /tmp/script.lua mykey somekey , arg1 arg2   -  person georgeliatsos    schedule 19.10.2018
comment
@gliatsos, пожалуйста, проверьте вышеприведенное описание хоть раз. Я уже делаю это с тем же для тестирования   -  person Jaswinder    schedule 19.10.2018
comment
Запуск этого скрипта возвращает (ноль). Поскольку вы не звоните populate_data, я не вижу, как вы добираетесь до строки 11.   -  person Itamar Haber    schedule 19.10.2018
comment
@ItamarHaber да, я не упомянул о вызове ссылки на pupulate_data из-за некоторых личных соображений, но да, это было вызвано. Я думаю, что это что-то связанное с lightuserdata для «значения», получающего «light-userdata@(nil)», но не уверен, как определить, что это «значение» равно нулю   -  person Jaswinder    schedule 19.10.2018
comment
@ItamarHaber, у вас большой опыт работы со сценариями Lua, и я очень признателен, если вы поможете мне в этом.   -  person Jaswinder    schedule 19.10.2018


Ответы (1)


TL;DR для значений, возвращаемых cjson.decode(), используйте cjson.null для сравнения со значением null JSON.

Объяснение: Lua использует nil в таблицах для обозначения удаленных записей. Если бы JSONinc nulls были преобразованы в Lunatic nils, декодированные объекты были бы повреждены. Поэтому библиотека cjson использует упрощенный тип пользовательских данных для представления null/nil.

У ваших call_data есть поле date_created, которое равно нулю, что вызывает ошибку.

Забавно то, что Redis, как и Lua, не будет хранить значение nil/null, поэтому вам придется либо игнорировать нулевые значения, либо использовать специальное значение в Redis для их пометки.

Предполагая, что вы будете игнорировать их, вот один из способов обойти это:

local call_data     = cjson.decode(ARGV[1])
local other_data    = cjson.decode(ARGV[2])
local data          = {}
local next          = next
local null          = cjson.null
local populate_data = function(source)
  if next(source) == nil then
    return
  end

  for property,value in pairs(source) do
    if value ~= null then
      redis.call('HSET', KEYS[2], property, value)
    end
  end
end
populate_data(call_data)
populate_data(other_data)

Кроме того, небольшой оптимизацией будет пакетное обновление, например:

  local payload = {}
  for property,value in pairs(source) do
    if value ~= null then
      table.insert(payload, property)
      table.insert(payload, value)
    end
  end
  redis.call('HSET', KEYS[2], unpack(payload))

P.S. если хотите, посмотрите на ReJSON, который я написал — он предназначен, чтобы помочь с тем, что кажется ты пытаешься сделать.

person Itamar Haber    schedule 20.10.2018