Манипулируем объектами

Объекты данных

Объекты данных используются для организации структуры сохраняемых данных. Перед тем как вы сможете сохранять данные в объект, вы должны создать объект, делается это при помощи команды object_new, который принимает единственный аргумент - имя объекта. После того как объект создан и до момента его сохранения командой object_save, вы можете работать с полями объекта, а именно записывать значения или список значений в поля командой object_field_set или даже другие объекты, используя специальный параметр в команде object_save. Если вы используете валидационную схему JSON в вашем диггере, команда записи объекта проверит ваш объект на валидность. При наличии валидационных ошибок объект не будет записан. Так же для проверки объекта без записи существует команда object_check, которая просто проверяет объект на валидность и в случае положительного результата исполняет команды из блока do, а в случае отрицательного - из блока else.

Допустимые команды:

          # СОЗДАНИЕ ОБЪЕКТА
- object_new: item
          
          # СОХРАНЕНИЕ ПОЛЯ
- object_field_set:
    # ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
    object: item
    # ИМЯ ПОЛЯ В КОТОРОЕ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
    # МОЖЕТ БЫТЬ КАК ЯВНЫМ НАПРИМЕР: somefield
    # ТАК И СОСТАВНЫМ НАПРИМЕР: somefield_<%somevar%>
    field: somefield
          
          # СОХРАНЕНИЕ ПОЛЯ С УКАЗАНИЕМ ТИПА
- object_field_set:
    # ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
    object: item
    # ИМЯ ПОЛЯ В КОТОРОЕ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
    # МОЖЕТ БЫТЬ КАК ЯВНЫМ НАПРИМЕР: somefield
    # ТАК И СОСТАВНЫМ НАПРИМЕР: somefield_<%somevar%>
    field: somefield
    # УКАЗЫВАЕМ ТИП ПОЛЯ (МОЖЕТ БЫТЬ: float, date ИЛИ int)
    type: float
    # И КОЛИЧЕСТВО ЗНАКОВ ПОСЛЕ ЗАПЯТОЙ
    precision: 2
          
          # СОХРАНЕНИЕ ДАННЫХ В ПОЛЕ ТИПА json array (PUSH)
- object_field_push:
    # ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
    object: item
    # ИМЯ ПОЛЯ В КОТОРОЕ НЕОБХОДИМО ЗАПИСАТЬ ДАННЫЕ
    # МОЖЕТ БЫТЬ КАК ЯВНЫМ НАПРИМЕР: somefield
    # ТАК И СОСТАВНЫМ НАПРИМЕР: somefield_<%somevar%>
    field: somefield
    # ПРОВЕРКА ДАННЫХ НА УНИКАЛЬНОСТЬ В ЭТОМ ПОЛЕ (ОПЦИОНАЛЬНО)
    # ЕСЛИ ДАННЫЕ УНИКАЛЬНЫ ПРОИСХОДИТ ЗАПИСЬ, ЕСЛИ НЕ УНИКАЛЬНЫ - НЕ ПРОИСХОДИТ
    unique: yes
          
          # СОХРАНЕНИЕ ОБЪЕКТА В ОБЪЕКТ
- object_save:
    # ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ В ОБЪЕКТ `anotherobj`
    name: item
   # ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ОБЪЕКТ `item`
    to: anotherobj
# ИЛИ
- object_save:
    # ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ В ОБЪЕКТ `anotherobj`
    name: item
    # ИМЯ ОБЪЕКТА В КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ ОБЪЕКТ `item`
    to: anotherobj
    # ЗАПИСЬ ОБЪЕКТА КАК ТИП json Object (ключ знаение)
    as: map
          
          # СОХРАНЕНИЕ ОБЪЕКТА
- object_save:
    # ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ЗАПИСАТЬ
    name: item
          
            # ПРОВЕРКА ОБЪЕКТА
  - object_check:
      # ИМЯ ОБЪЕКТА КОТОРЫЙ НЕОБХОДИМО ПРОВЕРИТЬ
      name: item
      # БЛОК КОМАНД, ВЫПОЛНЯЕМЫХ ПРИ ПОЛОЖИТЕЛЬНОМ РЕЗУЛЬТАТЕ ПРОВЕРКИ
      do:
      - register_set: All is good
      # БЛОК КОМАНД, ВЫПОЛНЯЕМЫХ ПРИ ОТРИЦАТЕЛЬНОМ РЕЗУЛЬТАТЕ ПРОВЕРКИ
      else:
      - exit
        

Запись объектов в объект может происходить по двум сценариям:
запись множества объектов в поле или запись одного объекта как хеш-таблицы.

Запись множества объектов в объект производится следующим образом:

              # СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul>
                    <li>A</li>
                    <li>B</li>
                    <li>C</li>
                    <li>D</li>
                </ul>'
- to_block
- find:
    path: ul
    do:
    # СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
    - object_new: item
    - find:
        path: li
        do:
        # СОЗДАДИМ ЕЩЕ ОДИН ОБЪЕКТ НО С ИМЕНЕМ `sub-item`
        - object_new: sub-item

        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `sub-item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sometext`
        - object_field_set:
            object: sub-item
            field: sometext

        # ЗАПИШЕМ ОБЪЕКТ `sub-item` В ОБЪЕКТ `item`
        - object_save:
            name: sub-item
            to: item

    # СОХРАНИМ ОБЪЕКТ `item`
    - object_save:
        name: item
              
              {
    "item": {
        "sub-item": [
          {
            "sometext": "A",
          },
          {
            "sometext": "B",
          },
          {
            "sometext": "C",
          },
          {
            "sometext": "D",
          }
        ]
    }
}
              

Запись объекта в объект как json map:

              # СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul>
                    <li>A</li>
                    <li>B</li>
                    <li>C</li>
                    <li>D</li>
                </ul>'
- to_block
- find:
    path: ul
    do:
    # СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
    - object_new: item
    - find:
        path: li
        do:
        # СОЗДАДИМ ЕЩЕ ОДИН ОБЪЕКТ НО С ИМЕНЕМ `sub-item`
        - object_new: sub-item

        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `sub-item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sometext`
        - object_field_set:
            object: sub-item
            field: sometext

        # ЗАПИШЕМ ОБЪЕКТ `sub-item` В ОБЪЕКТ `item` КАК json map
        - object_save:
            name: sub-item
            to: item
            as: map

    # ЗАПИШЕМ ОБЪЕКТ `item`
    - object_save:
        name: item
              
              {
    "item": {
        "sub-item" : {
            "sometext": "D"
    }
}
              

Обратите внимание!
В данном примере сценарий проходит по всем тегам li, но в финальную структуру данных попадает лишь последний элемент со значением D. Это происходит потому что поле будет последовательно перезаписано значениями всех элементов, в результате в поле останется лишь значение последнего элемента.

Пример корректного создания и записи обьектов:

              # КАЖДЫЙ РАЗ КОГДА МЫ ИТЕРИРУЕМ ПО БЛОКУ ЛОГИКА ПОВТОРЯЕТСЯ
# И ПОТОМУ КАЖДЫЙ РАЗ БУДЕТ СОЗДАН НОВЫЙ ОБЪЕКТ
- find:
    path: .somepath
    do:
    # СОЗДАЕМ ОБЪЕКТ С ИМЕНЕМ `someobj`
    - object_new: someobj

    # ЗАПОЛНЯЕМ РЕГИСТР ДАННЫМИ
    - parse

    # ЗАПИСЫВАЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `someobj`
    - object_field_set:
        object: someobj
        field: somefield

    # ПЕРЕЙДЕМ В ДРУГОЙ БЛОК И ЗАПИШЕМ ЧТО НИБУДЬ В ДРУГОЕ ПОЛЕ ОБЪЕКТА `someobj`
    # ВАЖНО! ЕСЛИ ДРУГОЙ БЛОК ВСЕГО ОДИН - ЗАПИСАННОЕ ЗНАЧЕНИЕ БУДЕТ ВЕРНО,
    # ЕСЛИ БЛОКОВ БУДЕТ НЕСКОЛЬКО, ТО В ПОЛЕ БУДЕТ ЗАПИСАНО ЗНАЧЕНИЕ С ПОСЛЕДНЕЙ ИТЕРАЦИИ
    # ОБ ЭТОМ ПОДРОБНЕЕ НИЖЕ, СЕЙЧАС ПЕРЕЙДЕМ ТОЛЬКО В 1 БЛОК
    - find:
        path: li:nth-of-type(1)
        do:
        - parse

        # ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `anotherfield` ОБЪЕКТА `someobj`
        - object_field_set:
            object: someobj
            field: anotherfield

    # ПЕРЕЙДЕМ ПО ПУТИ КОТОРЫЙ ВЕДЕТ ДО НЕСКОЛЬКИХ БЛОКОВ,
    # ЧТО БЫ ПО НИМ ПРОИТЕРИРОВАТЬ И ЗАПИСАТЬ ДАННЫЕ В ОБЪЕКТ `someobj`
    - find:
        path: .anotherpath
        do:
        # СОЗДАДИМ НОВЫЙ ОБЪЕКТ ДЛЯ ХРАНЕНИЯ ДАННЫХ ТЕКУЩЕГО БЛОКА
        - object_new: anotherobj

        # ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `anotherobj`
        - parse
        - object_field_set:
            object: anotherobj
            field: somefield

        # СОХРАНИМ ОБЪЕКТ `anotherobj` В ОБЪЕКТ `someobj`
        - object_save:
            name: anotherobj
            to: someobj

    # СОХРАНИМ ОБЪЕКТ `someobj`
    - object_save:
        name: someobj
              
              # ПРИВЕДЕМ ПРИМЕР КАК ДЕЛАТЬ НЕЛЬЗЯ :)
- find:
    path: .somepath
    do:
    # СОЗДАЕМ ОБЪЕКТ С ИМЕНЕМ `someobj`
    - object_new: someobj

    # ЗАПОЛНЯЕМ РЕГИСТ ДАННЫМИ
    - parse

    # ЗАПИСЫВАЕМ ЗНАЧЕНИК РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `someobj`
    - object_field_set:
        object: someobj
        field: somefield

    # ПЕРЕЙДЕМ ПО ПУТИ КОТОРЫЙ ВЕДЕТ ДО НЕСКОЛЬКИХ БЛОКОВ,
    # ЧТО БЫ ПО НИМ ПРОИТЕРИРОВАТЬ И ЗАПИСАТЬ ДАННЫЕ В ОБЪЕКТ `someobj`
    - find:
        path: .anotherpath
        do:
        # СОЗДАДИМ НОВЫЙ ОБЪЕКТ ДЛЯ ХРАНЕНИЯ ДАННЫХ ТЕКУЩЕГО БЛОКА
        - object_new: anotherobj

        # ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefield` ОБЪЕКТА `anotherobj`
        - parse
        - object_field_set:
            object: anotherobj
            field: somefield

        # СОХРАНИМ ОБЪЕКТ `anotherobj` В ОБЪЕКТ `someobj`
        - object_save:
            name: anotherobj
            to: someobj

    # ПЕРЕЙДЕМ В ДРУГОЙ БЛОК И ЗАПИШЕМ ЧТО НИБУДЬ В ДРУГОЕ ПОЛЕ ОБЪЕКТА `someobj`
    - find:
        path: li:nth-of-type(1)
        do:
        - parse

        # ЗАПИШЕМ ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `anotherfield` ОБЪЕКТА `someobj`
        - object_field_set:
            object: someobj
            field: anotherfield

        # А ТЕПЕРЬ, СОХРАНИМ ОБЪЕКТ `someobj` В ЭТОМ БЛОКЕ
        - object_save:
            name: someobj

    # ПРОБЛЕМА ЗАКЛЮЧАЕТСЯ В ТОМ, ЧТО ЕСЛИ НЕ БУДЕТ НАЙДЕНО НИ ОДНОГО БЛОКА ПО ПУТИ `li:nth-of-type(1)`
    # ОБЪЕКТ `someobj` НЕ БУДЕТ СОХРАНЕН, В ТАКОМ СЛУЧАЕ ВЫ ПОТЕРЯЕТЕ ВСЕ ДАННЫЕ ЗАПИСАННЫЕ В НЕГО ДО ЭТОГО МОМЕНТА.
    # ЭТО НЕЯВНАЯ ОШИБКА И ДИГГЕР БУДЕТ РАБОТАТЬ ВПОЛНЕ КОРРЕКТНО С ТАКОЙ ЗАПИСЬЮ, НО В ДАННЫХ ВОЗМОЖНЫ ПРОБЛЕМЫ.
              
              {
    "someobj": {
        "somefield" : "somedata",
        "anotherfield": "anotherdata",
        "anotherobj" : [
            {
                "somefield":"somedata"
            },
            {
                "somefield":"somedata"
            },
            ...
            ...
            ...
            {
                "somefield":"somedata"
            },
            {
                "somefield":"somedata"
            }
        ]
    }
}
              

Запись поля в объект с указанием типа (поддерживаются типы int, float, bool, string). Если тип опущен используется стандатный тип string:

              # СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul>
                    <li class="float">12.85</li>
                    <li class="int">158</li>
                    <li class="bool_false">false</li>
                    <li class="bool_true">true</li>
                </ul>'
- to_block
- find:
    path: ul
    do:
    # СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
    - object_new: item
    - find:
        path: .float
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `somefloat` С УКАЗАНИЕМ ТИПА `float`
        - object_field_set:
            object: item
            field: somefloat
            type: float

    - find:
        path: .int
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `someint` С УКАЗАНИЕМ ТИПА `int`
        - object_field_set:
            object: item
            field: someint
            type: int

    - find:
      path: .bool_false
      do:
      # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
      - parse
      # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `falsebool` С УКАЗАНИЕМ ТИПА `bool`
      - object_field_set:
          object: item
          field: falsebool
          type: bool

    - find:
      path: .bool_true
      do:
      # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
      - parse
      # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `truebool` С УКАЗАНИЕМ ТИПА `bool`
      - object_field_set:
          object: item
          field: truebool
          type: bool
          
    # ЗАПИШЕМ ОБЪЕКТ `item`
    - object_save:
        name: item
              
              {
    "item": {
        "somefloat": 12.85,
        "someint": 158,
        "falsebool": false,
        "truebool": true
    }
}
              

Запись поля в объект с объединением значений:

              # СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul class="int">
                    <li>125</li>
                    <li>158</li>
                </ul>
                <ul class="float">
                    <li>12.5</li>
                    <li>15.8</li>
                </ul>
                <ul class="default">
                    <li>sometext</li>
                    <li>15.8</li>
                </ul>'
- to_block
- find:
    path: ul.int
    do:
    # СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
    - object_new: item
    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `multint` С УКАЗАНИЕМ ТИПА `int`
        - object_field_set:
            object: item
            field: multint
            type: int
            joinby: "*" # УМНОЖЕНИЕ

    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `divint` С УКАЗАНИЕМ ТИПА `int`
        - object_field_set:
            object: item
            field: divint
            type: int
            joinby: "/" # ДЕЛЕНИЕ

    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `subint` С УКАЗАНИЕМ ТИПА `int`
        - object_field_set:
            object: item
            field: subint
            type: int
            joinby: "-" # ВЫЧИТАНИЕ

    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sumint` С УКАЗАНИЕМ ТИПА `int`
        - object_field_set:
            object: item
            field: sumint
            type: int
            joinby: "+" # СЛОЖЕНИЕ

    # СОХРАНИМ ОБЪЕКТ `item`
    - object_save:
        name: item
              
              {
    "item": {
        "divint": 0,
        "multint": 19750,
        "subint": -33,
        "sumint": 283
    }
}
              
              # СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul class="int">
                    <li>125</li>
                    <li>158</li>
                </ul>
                <ul class="float">
                    <li>12.5</li>
                    <li>15.8</li>
                </ul>
                <ul class="default">
                    <li>sometext</li>
                    <li>15.8</li>
                </ul>'
- to_block
- find:
    path: ul.float
    do:
    # СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
    - object_new: item
    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `multfloat` С УКАЗАНИЕМ ТИПА `float`
        - object_field_set:
            object: item
            field: multfloat
            type: float
            joinby: "*" # УМНОЖЕНИЕ
            precision: 2

    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `divfloat` С УКАЗАНИЕМ ТИПА `float`
        - object_field_set:
            object: item
            field: divfloat
            type: float
            joinby: "/" # ДЕЛЕНИЕ
            precision: 3

    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `subfloat` С УКАЗАНИЕМ ТИПА `float`
        - object_field_set:
            object: item
            field: subfloat
            type: float
            joinby: "-" # ВЫЧИТАНИЕ
            precision: 4

    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `sumfloat` С УКАЗАНИЕМ ТИПА `float`
        - object_field_set:
            object: item
            field: sumfloat
            type: float
            joinby: "+" # СЛОЖЕНИЕ
            precision: 5

    # СОХРАНИМ ОБЪЕКТ `item`
    - object_save:
        name: item
              
              {
    "item": {
        "divfloat": 0.7911392405063291,
        "multfloat": 197.5,
        "subfloat": -3.3000000000000007,
        "sumfloat": 28.3
    }
}
              
              # СОЗДАДИМ ТЕСТОВЫЙ БЛОК
- register_set: '<ul class="int">
                    <li>125</li>
                    <li>158</li>
                </ul>
                <ul class="float">
                    <li>12.5</li>
                    <li>15.8</li>
                </ul>
                <ul class="default">
                    <li>sometext</li>
                    <li>15.8</li>
                </ul>'
- to_block
- find:
    path: ul.default
    do:
    # СОЗДАДИМ ОБЪЕКТ С ИМЕНЕМ `item`
    - object_new: item
    - find:
        path: li
        do:
        # ЗАПОЛНИМ РЕГИСТР ДАННЫМИ
        - parse

        # ЗАПИШЕМ В ОБЪЕКТ `item` ЗНАЧЕНИЕ РЕГИСТРА В ПОЛЕ `default` С УКАЗАНИЕМ РАЗДЕЛИТЕЛЯ
        - object_field_set:
            object: item
            field: default
            joinby: "*" # РАЗДЕЛИТЕЛЬ

    # СОХРАНИМ ОБЪЕКТ `item`
    - object_save:
        name: item
              
              {
    "item": {
        "default": "sometext*15.8"
    }
}
              

Команды object_save и object_check поддерживают специальный режим апдейта. По умолчанию этот режим отключен и для его включения необходимо передать параметр mode со значением update, так, как показано в примере внизу. Вместе с параметром mode, вам нужно также передать параметр primary_key с именем поля вашего датасета, которое будет использоваться в качестве первичного (уникального) ключа записи. В этом режиме, система сравнивает контрольную сумму последней сохраненной записи с заданным ключем с контрольной суммой новой записи. Если суммы совпадают, запись не будет записана, так как система посчитает ее дубликатом уже когда-то собранной записи. В противном случае, новая запись будет сохранена и контрольная сумма для ключа в кэше будет обновлена до текущей.

            # SAVE OBJECT `item`
- object_save:
name: item
mode: update
primary_key: title
            

В следующей главе мы рассмотрим методы для работы с DOM структурой документа.