Как изменить значение и ввести JSON с помощью объектива аргонавта?

Предположим, у вас есть следующий простой документ JSON:

       {
         "key" : "val1"
       }

Я хотел бы обновить значение «ключа», но в то же время изменить его тип, поэтому из строки измените его на int. Теперь, используя HCursor, как показано ниже, можно и прямо сделать это:

 val cursor = js.hcursor
 val position = (cursor --\ "key") >-> (_ => jNumber(1))

«Отменив» вышеуказанную позицию, я получаю новый json, где «ключ» имеет числовое значение, а не строку, что идеально.

Можно ли сделать то же самое с линзами? Я попытался сделать следующее:

val lense = jObjectPL >=>
          jsonObjectPL("key") >=>
          jNumberPL
lense.mod(_ => JsonBigDecimal(1), js)

Но хотя я не получаю ошибку, это также не работает, в конце концов я получаю исходный документ json без изменений. Однако, если я уважаю тип данных, все работает так, как должно. Есть ли причина, по которой линзы следует использовать только для модификаций одного и того же типа данных? Или я просто делаю что-то ужасное неправильно :)


person cpard    schedule 21.06.2016    source источник


Ответы (1)


Нет, ничего страшного — вы почти у цели. Проблема в том, что этот путь:

jObjectPL >=> jsonObjectPL("key") >=> jNumberPL

Переход к номеру JSON по адресу "key". Ваш js не имеет номера JSON в ключе, поэтому линза ни на что не указывает, и модификация ни на что не влияет.

Вы можете исправить это, просто удалив последний шаг из объектива:

val lens = jObjectPL >=> jsonObjectPL("key")

Это просто переходит к полю "key", но не накладывает ограничений на то, какое это значение JSON. Затем вы можете изменить его на все, что хотите:

scala> val lens = jObjectPL >=> jsonObjectPL("key")
lens: scalaz.PLensFamily[...

scala> lens.mod(_ => jNumber(JsonBigDecimal(1)), js)
res0: argonaut.Json = {"key":1}

Обратите внимание, что поскольку линза указывает на значение Json, а не на JsonNumber, вам придется обернуть JsonBigDecimal в jNumber, чтобы типы выровнялись.

person Travis Brown    schedule 21.06.2016
comment
Спасибо за быстрый ответ @Travis! очень признателен. Читая документацию для объективов и Argonaut, у меня сложилось впечатление, что вы всегда должны определять тип данных JSON, который вы ожидаете. Но я думаю, что это часть человеческой природы иногда усложнять вещи :) - person cpard; 21.06.2016
comment
@cpard Да :). В этом случае вы ожидаете строку JSON в этой позиции, но если вы добавите jStringPL к линзе, вы не сможете изменить этот тип. - person Travis Brown; 21.06.2016