3. Доступ к данным / 3.1. Язык запросов
3. Доступ к данным / 3.1. Язык запросов

3.1. Язык запросов

3.1. Язык запросов

Язык запросов системы основан на GraphQL. При помощи него можно делать выборки объектов и ходить по связям.

3.1.1. Выборка агрегатов

Все агрегаты (объекты логического типа «Aggregate» — см. подробнее в описании модели) доступны для запроса по своему имени типа. Например, если в модели определен тип Book, объекты этого типа можно выбрать вот так:

{
  Book(ISBN: "978-3-16-148410-0") {
      title
      year
      author {
          first_name
          last_name
      }
  }
}

Здесь параметр запроса ISBN соответствует индексу ISBN для типа Book. Проверка условия выполняется на полное совпадение.

В одном запросе можно также указывать несколько индексов, в таком случае запрос будет искать объекты, удовлетворяющие всем условиям одновременно (логическая операция И).

{
  Book(year: 2018, issuing_country: "USA") {
      title
      year
      author {
          first_name
          last_name
      }
  }
}

Для запросов такого рода доступны только индексированные поля. Фильтровать по обычным полям таким способом не получится.

Для запроса по мультиколоночному индексу используется массив значений. Допустим для Агрегата Book создан индекс fullname включающий в себя author.first_name и author.last_name, тогда запрос для вывода автора будет выглядеть так:

{
  Book(fullname:['John', 'Snow']) {
    title
    year
  }
}

3.1.2. Выборка со сравнением

Выборки поддерживают операции сравнения в виде суффиксов в именах индексов.

Например для получения всех книг выпущенных после 2008 года можно использовать запрос

{
  Book(year_gt: 2008) {
    title
    year
    author {
      first_name
      last_name
    }
  }
}

Поддерживаются следующие операторы сравнения

  • _gt (Greater Than) строго больше

  • _ge (Greater than or Equal) больше либо равно

  • _lt (Less Than) строго меньше

  • _le (Less than or Equal) меньше либо равно

Данные суффиксы поддерживаются и для мультиколоночных индексов. Предположим что есть индекс содержащий в себе year и month - year_month. Тогда для получения книг выпущенных после июля 2008 года запрос будет такой

{
  Book(year_month_gt: [2008, 07]) {
    title
    year
    author {
      first_name
      last_name
    }
  }
}

3.1.3. Выборка Агрегатов по связям

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

{
  Book(year_month_gt: [2008, 07]) {
    title
    year
    author(first_name: "Anton") {
      first_name
      last_name
    }
 }

В этом случае будут выбраны все книги старше июля 2008 года, а авторы показаны только с именем Антон.

Данный вид запроса аналогичен SQL LEFT OUTER JOIN.

3.1.4. Пагинация

Для пагинации мы используем метод с непрозрачными курсорами, похожий на тот, что описан Здесь.

Прототип запроса выглядит так:

MyType(first:2, after:$cursor)

Где:

  • first указывает максимальное количество возвращаемых элементов (по умолчанию 10)

  • after говорит с какого элемента продолжить выполнение запроса

В after как раз и передается «непрозрачный курсор». Непрозрачный курсор – это строка, о смысле которой пользователь не должен задумываться. Все, что нужно знать – это то, что используя эту строку, сервер может продолжить выполнение запроса с нужного места.

Каждый агрегат имеет специальное синтетическое поле cursor, доступное через graphql. В дизайне пагинации TDG было решено перенести cursor на уровень агрегата, что позволяет не вводить промежуточных уровней запроса edges и node, как это предлагается делать В руководстве.

Пример первого запроса:

{
  CouponPayment(first: 2) {
    header {
      metadata {
        object_id
      }
    }
    cursor
  }
}

Ответ:

{
  "data": {
    "CouponPayment": [
      {
        "header": {
          "metadata": {
            "object_id": "1985222"
          }
        },
        "cursor": "gaJwa5GnMTk4NTIyMg=="
      },
      {
        "header": {
          "metadata": {
            "object_id": "1985223"
          }
        },
        "cursor": "gaJwa5GnMTk4NTIyMw=="
      }
    ]
  }
}

Теперь, чтобы продолжить получение следующей порции данных, нужно взять поле cursor с последнего объекта из результата (в данном случае – "gaJwa5GnMTk4NTIyMw==") и передать его в аргумент after:

{
  CouponPayment(first: 2, after: "gaJwa5GnMTk4NTIyMw==") {
    header {
      metadata {
        object_id
      }
    }
    cursor
  }
}

Для обратной пагинации необходимо использовать отрицательное число first. В данном случае система вернет предыдущие объекты относительно after. Обратная пагинация некольцевая, с помощью неё нет возможности получить последний объект множества выборки смещаясь от первого.

Пагинация также доступна для запроса по связям. Например:

{
  Book(year_month_gt: [2008, 07]) {
    title
    year
    author(first_name: "Anton" first: 2) {
      first_name
      last_name
    }
 }

3.1.5. Ограничения запросов

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

  • запрос не должен проходить больше scanned строк;

  • запрос не должен возвращать больше returned строк.

Данные ограничения превентивно требуют качественного написания запросов, являясь по сути аналогом <<профилирования медленных запросов>>.

Настройка параметров выполняется с помощью graphql запросов и мутаций.

Получить текущие значения ограничителей:

query power {
  config {
    hard_limits {
      scanned
      returned
    }
  }
}

Нарастить ограничители:

mutation gimme_tha_power {
  config {
    hard_limits(scanned: 300000 returned:300000) {
      scanned
      returned
    }
  }
}