Top.Mail.Ru
Tdg » 1.6 » 1. Руководство по разработке приложений » 1.3. Программный интерфейс репозитория
 
1. Руководство по разработке приложений / 1.3. Программный интерфейс репозитория
1. Руководство по разработке приложений / 1.3. Программный интерфейс репозитория

1.3. Программный интерфейс репозитория

1.3. Программный интерфейс репозитория

Пользовательский код в TDG исполняется в изолированной среде – так называемой «песочнице» (sandbox). При этом для доступа к данным должны использоваться функции программного интерфейса репозитория (repository API).

Все запросы к данным в TDG от внешних информационных систем, включая GraphQL запросы (а также запросы, выполняемые при помощи вкладки GraphQL), также реализованы на основе функций программного интерфейса репозитория.

Основные функции программного интерфейса репозитория включают в себя выборки разной сложности, изменение и обработку данных, а также добавление отложенных работ:

repository.get(type_name, index_name, value, options, context)

repository.find(type_name, filter, options, context)

repository.map_reduce(type_name, filter, version, map_fn, combine_fn, reduce_fn, opts)

repository.update(type_name, filter, updaters, options, context)

repository.delete(type_name, filter, options, context)

repository.call_on_storage(type_name, index_name, value, func_name, func_args, options, context)

repository.put(type_name, object, options, context)

repository.push_job(name, arguments, options, context)

где:

  • get – выборка по ключу или индексу;
  • find – выборка по полям объектов одного типа, включая несколько условий;
  • map_reduceсложная агрегация по кластеру;
  • updateобновление объектов модели;
  • deleteудаление объектов модели;
  • call_on_storage – вызов функции на хранилище для локальной обработки данных;
  • put – вставка нового или замена существующего объекта;
  • push_job – добавление внутренней задачи на обработку данных в список отложенного исполнения.

Функции get, find, update, delete поддерживают порядковую нумерацию страниц («пагинацию») с помощью параметров first и after.

Чтобы фильтровать объекты, запросы (все, кроме get) используют условия-предикаты (filter) – булевы выражения, синтаксис которых описан ниже.

1.3.1. Синтаксис предикатов

В запросах предикаты (filter) записываются в виде:

{{left, comparator, right}, ...}

где:

  • left и right – это левая и правая части выражения.

    Правая часть выражения (right) может содержать:

    • либо полный путь к полю объекта ($foo.bar), где имя поля начинается со знака $;
    • либо строковое или численное значение.

    Левая часть (left) может содержать только полный путь к полю.

  • comparator – оператор сравнения: ">", ">=", "==", "<=" или "<".

Если в предикате несколько условий, по умолчанию они объединяются логической операцией and (конъюнкцией).

Примеры предикатов:

{{"$id", ">", 10}}
{{"$id", ">", 10}, {"$id", "<", 100}}
{{"$name", "==", "foo"}, {"$birth_year", "==", 1990}}
{{"$name", "==", "foo"}, {"$reg_date", "==", {1990, 04, 23}}}

1.3.2. Общее хранилище

Для передачи объектов между функциями и экземплярами TDG используйте общее хранилище (shared storage). При помощи следующей команды подключите существующее или создайте новое (если с таким именем ещё не существует) общее хранилище:

local shared_storage_object = shared_storage.new('some_namespace')

Переменная shared_storage_object в данном примере содержит указатель на созданное общее хранилище.

Примечание

При создании общего хранилища создаётся спэйс, который хранится на одном из репликасетов с ролью storage. Однако персистентность данных в общем хранилище не гарантируется – данные из него могут быть потеряны, например, при перезапуске кластера.

Данные в общее хранилище помещаются в формате key, value, например следующей командой:

shared_storage_object:set('abc', 123)

где „abc“ - это ключ (key), а 123 - значение (value).

Для получения данных из общего хранилища выполните следующую команду:

shared_storage_object:get('abc')

1.3.3. Исторические данные

Запросы позволяют получить или обработать объекты, которые предшествуют или равны определённой версии. За это отвечает параметр version в options.

Примечание

Пример: Допустим существуют версии 1, 3 и 5 объекта, а мы запросили версию 4. В таком случае, мы получим версию либо равную запрошенной, либо ближайшую предшествующую, в данном случае версию 3.

При получении данных параметр version определяет версию получаемого объекта. Если параметр version не задан, то будет получена последняя версия объекта.

При обновлении данных параметр version определяет изменяемую версию объекта. Если задано значение параметра version, то запрос получит указанную версию объекта (или ближайшую предшествующую, смотри пример выше), выполнит обновление и сохранит результат с той же версией. Если параметр version не задан, то запрос получит последнюю версия объекта, обновит её и сохранит с новой версией, значение которой будет взято по умолчанию (большое целое монотонно возрастающее число).

При вставке (добавлении или замене) объекта параметр version определяет версию объекта, который будет добавлен или заменён. Если параметр version не задан, то используется значение по умолчанию (см. выше).

При удалении данных параметр version определяет удаляемую версию объекта. Если параметр version не задан, то будет удалена последняя версия объекта.

Для запросов на выборку или удаление объектов (find или delete), при установленном флаге all-versions (значение True) обработка выполняется для всех версий объекта. Если задан параметр version, то обрабатываются все версии меньше или равные заданной.

1.3.4. Оптимистичные блокировки

В случае конкурентной модификации объекта (когда изменения в один объект могут вноситься параллельно из разных обработчиков, что может вызывать конфликты) необходимо использовать механизм оптимистичных блокировок, основанный на версиях объектов. Для этого задайте значение only_if_version в options и запрос выполнится только в случае, если данная версия объекта является последней и совпадает с заданной в запросе.

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

repository.put("users", {id = "100500", name = "Kirito777"}, {version = 6, only_if_version = 5})

Этот запрос попытается выполнить поиск по первичному ключу (в данном случае – id). Если запись с таким значением первичного ключа будет найдена, то она будет обновлена только в том случае, если версия объекта в системе на момент исполнения совпадёт со значением, переданным в параметре only_if_version (в данном примере это 5). После успешного исполнения запроса последняя версия объекта станет равна 6. Если запись с переданным значением первичного ключа отсутствует, то новая запись добавлена не будет, так как версия несуществующей записи не может быть равна 5.

1.3.5. Управление объектами модели

Данные в TDG хранятся с использованием понятий агрегат/сущность/значение. Агрегаты имеют свой уникальный идентификатор (первичный ключ), на основе которого они распределяются по хранилищам. См. подробнее.

Приложение TDG может управлять объектами модели при помощи запросов на обновление (update), добавление (put) и удаление (delete).

1.3.5.1. Запрос на обновление данных

Запрос на обновление данных (update) поддерживает версионирование и выполняется в две стадии:

  • исполнение запроса на каждом хранилище, которое может содержать объекты по условию, передаваемому аргументом filter;
  • сбор результатов на роутере.

Синтаксис update-запроса

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

repository.update(type_name, filter, updaters, options, context)

где:

  • type_name – имя типа объекта для обновления;

  • filter – список условий-предикатов для выбора (фильтрации) объектов указанного типа;

  • updaters – список обновлений для объекта, состоящий из:

    • списка мутаторов {{mutator, path, new_value}, ...}, где:

      • mutator – имя мутатора, например:

        • set – устанавливает значение;
        • add – увеличивает значение на указанное число;
        • sub – уменьшает значение на указанное число.
      • path – строковый путь до поля объекта с точкой-разделителем (.).

        Путь до объекта(ов) массива должен включать индекс массива или символ * для захвата всех подобъектов.

      • new_value – новое значение.

  • options – параметры для управления запросом:

    • first – количество элементов для обновления;
    • after – курсор пагинации на первый элемент;
    • version – версия объекта для основы;
    • only_if_version – проверка имеющейся версии перед вставкой;
    • dont_skip_deleted – использовать в поиске удаленные версии объектов.
  • context – контекст выполнения запроса:

    • tenant – тенант.

Примеры update-запроса

Для модели, рассмотренной в примере:

  • Чтобы обновить имя клиента с идентификатором 42, используйте следующий запрос:

    repository.update(
     "Client",
     {{"$id", "==", 42}},
     {{"set", "first_name", "John"},
      {"set", "last_name", "Doe"}})
    
  • Если у того же клиента истек срок действия первого паспорта и необходимо обновить соответствующее поле expired_flag, используйте следующий запрос:

    repository.update(
     "Client",
     {{"$id", "==", 42}},
     {{"set", "passports.1.expired_flag", "true"}}
    

    где .1. – индекс массива, содержащего экземпляры сущности Passport агрегата Client, т.е. первый паспорт клиента.

1.3.5.2. Запрос на добавление данных

Запрос put позволяет вставить новые данные или заменить существующие. Он поддерживает версионирование и оптимистичные блокировки.

Если отсутствует параметр version, то используется значение по умолчанию (большое целое монотонно возрастающее число).

При заданном параметре version запрос выполняет добавление или замену объекта с заданной версией (обычно используется целое число).

При указанном параметре only_if_version запрос добавляет или заменяет объект только в том случае, если последняя версия объекта совпадает с указанной.

Синтаксис put-запроса

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

repository.put(type_name, object, options, context)

где:

  • type_name – имя типа объекта для обновления;
  • object – объект для вставки;
  • options – параметры для управления запросом:
    • version – версия объекта.
    • only_if_version – проверка имеющейся версии перед вставкой.

Пример запроса на добавление объекта

repository.put("users", {id = "100500", name = "Kirito777"})

Данный запрос из примера добавит новый объект с первичным ключом id равным 100500, если таковой ещё не существует. При этом значение параметра version будет равным значению по умолчанию (большое целое монотонно возрастающее число). Если объект с таким первичным ключом уже есть, то будет добавлена новая версия объекта, со значением параметра version, равным значению по умолчанию.

1.3.5.3. Запрос на удаление объектов модели

Чтобы прозрачно и удобно исключить объект из потенциальных результатов запросов, используйте запрос на удаление (delete). Он помещает объект или его версию в «удаленное состояние» (добавляя флаг delete:true), что исключает его из выборки.

Запрос на удаление поддерживает версионирование и оптимистичные блокировки.

Синтаксис delete-запроса

Чтобы удалить объект, используйте следующий запрос:

repository.delete(type_name, filter, options, context)

где:

  • type_name имя типа объекта для удаления.
  • filter – список условий-предикатов для выбора (фильтрации) объектов указанного типа.
  • options – параметры для управления запросом:
    • first – количество элементов для удаления.
    • after – курсор пагинации на первый элемент.
    • version – версия объекта для копирования в удаленное состояние.
    • only_if_version – проверка имеющейся версии перед вставкой.
    • all-versions – этот флаг для функции удаления (delete) нельзя использовать без флага permanent delete.
    • permanent_delete – при установленном флаге (значение True) происходит физическое удаление информации об объекте из TDG. Используется вместе с флагом all-versions.
  • context – контекст выполнения запроса:
    • tenant – тенант

Пример delete-запроса

Чтобы удалить клиентов с именем «QWERTY» для модели из примера, используйте следующий запрос:

repository.delete(
 "Client",
 {{"$first_name", "==", "QWERTY"}})

В результате такого запроса все объекты, удовлетворяющие условию (first name равное QWERTY), будут дополнены новой версией (значение версии по умолчанию) с флагом delete:true.