Представьте, что у вас есть хранилище данных с REST-интерфейсом. Пусть в нем хранится информация о книгах и вы хотите вывести список всех книг. Можно сделать метод «books», который будет возвращать нам список книг. Но при отображении списка обычно есть паджинация или ленивая подгрузка данных, а еще пользовать хочет фильтровать и сортировать данные. Когда мы добавляем поддержку мобильных устройств у нас появляется еще потребность как-то ограничить объем получаемых данных не передавая часть полей. Всю эту информацию должен уметь понимать почти любой метод получения списка объектов, т.к. списки отображаются с помощью специального виджета. И тут нам на помощь приходит Resource Query Language.
Resource Query Language (RQL) — это язык запросов, разработанный для использования в URI при работе с объекто-подобными структурами данных. С помощью RQL клиент может запрашивать у сервера список объектов соответствующих определенным правилам, т.е., по сути, это синтаксис, который описывает как запрашивать данные. Например, запрос выбирающий все книги авторства Перумова может быть записан как
RQL можно рассматривать, в основном, как набор вложенных операторов, каждый из которых имеет множество аргументов. Он рассчитан на очень простую, но расширяемую грамматику, которая может быть использована в валидном URL запросе.
RQL выражение содержит функции запроса или операторы сравнения, соединенные логическими операторами.
Сначала разберем типовые сценарии. Для лучшего понимания будем сравнивать с аналогичными командами в MongoDB.
Пусть у нас есть список книг:
Выведем все книги из серии «Кольцо тьмы». В MongoDB мы бы сделали это так:
в RQL это будет выглядеть так:
или
Такой запрос вернет нам три книги.
Теперь более сложный запрос: нам надо вывести все книги серии «Кольцо тьмы» изданные в 1995 году.
В MongoDB:
В RQL:
Предыдущие запросы применялись к простым объектам. Но документы могут быть очень сложными по структуре. Например, добавим в нашу библиотеку новую книгу:
Здесь определяется вложенный объект с ключом
В MongoDB:
В RQL:
Со временем наша библиотека выросла. Список книг не помещается на экран и мы решили показывать его постранично.
В MongoDB мы можем получить второй десяток записей следующим образом:
В RQL:
Но показывать постранично мало. Еще хочется сортировать данные.
В MongoDB это будет:
В RQL:
Базовые функции стандарта:
Больше существующих операторов можно найти в официальной документации.
В технологии APS в RQL добавлена новая функция:
И еще три специфичные для APS функции:
Логические операторы позволяют посредством булевой логики объединить две и больше функций запроса. Все стандартные логические операторы имеют короткие алиасы.
В технологии APS в RQL также добавлен новый логический оператор отрицания:
Примечание
Оператор сравнения используется для фильтрации объектов посредством сравнения одного из их свойств с заданным значением.
Строковые типы сравниваются в лексикографическом порядке.
Функции запросов и операторы сравнения могут содержать следующие значения:
Функции-значения — это функции, возвращающие особые значения вроде
Существует большое количество реализации парсеров RQL на различных языках программирования.
Реализация на JavaScript кроме парсера содержит еще и движок, который умеет применять RQL-запрос к массиву объектов.
Оригинальная реализация RQL на JavaScript есть в npmjs: https://www.npmjs.com/package/rql
Реализация с добавленной нами функциональностью также доступна через npm: https://www.npmjs.com/package/aps-rql
Resource Query Language (RQL) — это язык запросов, разработанный для использования в URI при работе с объекто-подобными структурами данных. С помощью RQL клиент может запрашивать у сервера список объектов соответствующих определенным правилам, т.е., по сути, это синтаксис, который описывает как запрашивать данные. Например, запрос выбирающий все книги авторства Перумова может быть записан как
eq(author,Перумов)
или в обычном формате URL: author=Перумов
.RQL можно рассматривать, в основном, как набор вложенных операторов, каждый из которых имеет множество аргументов. Он рассчитан на очень простую, но расширяемую грамматику, которая может быть использована в валидном URL запросе.
Как использовать RQL
RQL выражение содержит функции запроса или операторы сравнения, соединенные логическими операторами.
Типовые сценарии
Сначала разберем типовые сценарии. Для лучшего понимания будем сравнивать с аналогичными командами в MongoDB.
Пусть у нас есть список книг:
[
{ title: "Эльфийский клинок", year: 1993, series: "Кольцо тьмы" },
{ title: "Чёрное копьё", year: 1993, series: "Кольцо тьмы" },
{ title: "Адамант Хенны", year: 1995, series: "Кольцо тьмы" },
{ title: "Воин Великой Тьмы", year: 1995, series: "Летописи Хьёрварда" }
]
Выведем все книги из серии «Кольцо тьмы». В MongoDB мы бы сделали это так:
db.users.find({series: "Кольцо тьмы"})
в RQL это будет выглядеть так:
eq(series, "Кольцо тьмы")
или
series="Кольцо тьмы"
Такой запрос вернет нам три книги.
Теперь более сложный запрос: нам надо вывести все книги серии «Кольцо тьмы» изданные в 1995 году.
В MongoDB:
db.users.find({series: "Кольцо тьмы", year: 1995})
В RQL:
eq(series, "Кольцо тьмы"),eq(year, 1995)
Предыдущие запросы применялись к простым объектам. Но документы могут быть очень сложными по структуре. Например, добавим в нашу библиотеку новую книгу:
{ title: "Воин Великой Тьмы", year: 1995, series: "Летописи Хьёрварда", translations: { language: "English", title: "Godsdoom" } }
Здесь определяется вложенный объект с ключом
translations
. И чтобы найти все книги переведенные на английский язык, нам надо использовать точку.В MongoDB:
db.users.find({"translations.language": "English"})
В RQL:
eq(translations.language, "English")
Со временем наша библиотека выросла. Список книг не помещается на экран и мы решили показывать его постранично.
В MongoDB мы можем получить второй десяток записей следующим образом:
db.users.find().skip(10).limit(10)
В RQL:
limit(10,10)
Но показывать постранично мало. Еще хочется сортировать данные.
В MongoDB это будет:
db.users.find().sort({title: 1})
В RQL:
sort(+title)
Функции
Базовые функции стандарта:
Функция | Описание |
---|---|
Выбирает объекты, у которых значение указанного свойства входит в заданный массив свойств. Пример: in(name,(Silver,Gold)) |
|
Выбирает объекты, у которых значение указанного свойства не входит в заданный массив свойств. Пример: out(name,(Platinum,Gold)) |
|
Возвращает заданное количество (number) объектов начиная с определённой (start) позиции. Пример: limit(0,2) |
|
sort (<list of properties with + or — prefix>) | Сортирует список объектов по заданным свойствам (количество свойств неограниченно). Сначала список сортируется по первому из заданных свойств, затем по второму, и так далее. Порядок сортировки определяется префиксом: + — по возрастанию, — — по убыванию. Пример: sort(+memory,-diskspace) |
Обрезает каждый объект до набора свойств, определенных в аргументах. Пример: select(name,user) |
|
Возвращает набор значений из указанного поля всех объектов. Пример: values(ve.name) |
|
Возвращает количество записей. Пример: in(name,(Silver,Gold))&count() |
|
Возвращает максимальное значение из указанного поля всех объектов. Пример: max(ve.memory) |
|
Возвращает минимальное значение из указанного поля всех объектов. Пример: min(ve.memory) |
Больше существующих операторов можно найти в официальной документации.
В технологии APS в RQL добавлена новая функция:
Функция | Описание |
---|---|
Ищет заданный паттерн (pattern) в заданном свойстве (property). Эта функция аналогична оператору SQL LIKE, хоть и использует символ * вместо % . Чтобы определить в паттерне сам символ * , он должен быть процентно-кодированным, то есть надо писать %2A вместо * , см. примеры. Кроме того, в паттерне можно использовать символ ? , обозначающий, что любой символ в этой позиции является валидным.Примеры: like(firstName,Jo*) |
И еще три специфичные для APS функции:
Функция | Описание |
---|---|
Возвращает список объектов (ресурсы и типы), реализующих базовый тип и включающих в себя сам базовый тип. Пример: implementing (http://aps-standard.org/samples/user-mgmt/offer/1.0) |
|
Возвращает список типов, которые реализованы производным типом (derived type), включая сам производный тип. Пример: composing(http://aps-standard.org/samples/user-mgmt/offer/1.0) |
|
Возвращает список ресурсов, которые связаны тем ресурсом, чей ID указан в качестве аргумента. APS-контроллер ищет все ссылки на ресурсы, включая внутренние системные ссылки. Например, актор admin/owner/referrer, имеющий доступ к ресурсу, тоже будет считаться «связанным» ресурсом. Примеры: linkedWith(220aa29a-4ff4-460b-963d-f4a3ba093a0a) |
Логические операторы
Логические операторы позволяют посредством булевой логики объединить две и больше функций запроса. Все стандартные логические операторы имеют короткие алиасы.
Оператор | Алиас | Примеры |
---|---|---|
& , |
and (limit(0,2),like(name,*L*)) Значение Выбирает первые два предложения, имена которых соответствуют нечувствительному к регистру паттерну *L* |
|
or (<quеry>,<quеry>,...) | | ; |
or(like(description,*free*),in(name,(Silver,Gold))) Значение Выбирает все предложения, описания (description) которых соответствуют паттерну *free* , а также те, чьё имя Silver или Gold . |
В технологии APS в RQL также добавлен новый логический оператор отрицания:
Оператор | Примеры |
---|---|
not (<quеry>) | not(like(name,*free*)) Значение Выбирает все предложения, за исключением тех, чьё имя соответствует Хабр и Гиктаймс — RQL паттерну *free* . |
Примечание
- Оператор
and
является неявным RQL-оператором верхнего уровня. Например, выражениеhttp://hosting.com?and(arg1,arg2,arg3)
эквивалентноhttp://hosting.com?arg1,arg2,arg3
. - У оператора and приоритет выше, чем у or. Поэтому при использовании алиасов нужно заключать объединённые запросы в круглые скобки, тем самым определяя необходимый порядок обработки. Например,
implementing(<typе>),(prop1=eq=1|prop2=ge=2)
.
Операторы сравнения
Оператор сравнения используется для фильтрации объектов посредством сравнения одного из их свойств с заданным значением.
Оператор | Алиас | Примеры |
---|---|---|
=eq= | eq(aps.status,aps:ready) Значение Выбирает все объекты, чей aps.status имеет значение aps:ready . |
|
=ne= | ne(aps.status,aps:ready) Значение Выбирает все объекты, чей aps.status имеет значение aps:ready . |
|
=gt= | implementing(http://aps-standard.org/samples/user-mgmt/offer),hardware.memory=gt=1024) Значение Выбирает все предложения (offers), предоставляющие hardware.memory больше 1024. |
|
=ge= | implementing(http://aps-standard.org/samples/user-mgmt/offer),hardware.memory=ge=1024) Значение Выбирает все предложения (offers), предоставляющие hardware.memory больше или равно 1024. |
|
=lt= | implementing(http://aps-standard.org/samples/user-mgmt/offer),hardware.CPU.number=lt=16) Значение Выбирает все предложения (offers), предоставляющие hardware.CPU.number меньше 16. |
|
=le= | implementing(http://aps-standard.org/samples/user-mgmt/offer),hardware.CPU.number=le=16) Значение Выбирает все предложения (offers), предоставляющие hardware.CPU.number меньше или равно 16. |
Строковые типы сравниваются в лексикографическом порядке.
Значения
Функции запросов и операторы сравнения могут содержать следующие значения:
- Строковые (с использованием URL-кодирования)
- Числа
- Даты (в формате ISO UTC без двоеточия)
- Булевы
- Функции-значения (Value functions)
Функции-значения — это функции, возвращающие особые значения вроде
null
, true
, false
или пустое строковое значение. Все они применимы к определённым типам данных.Функция-значение | Применимые типы | Описания | Примеры |
---|---|---|---|
null() | Любой тип | Задаётся, если значение null |
name=eq=null() |
true() false() |
Булевы | Задаётся, если значение true или false |
disabled=eq=false() |
empty() | Строковые | Задаётся, если строковое значение является пустым (не null , но не содержит никаких символов) |
addressPostal.extendedAddress=eq=empty() |
Использование
Существует большое количество реализации парсеров RQL на различных языках программирования.
Реализация на JavaScript кроме парсера содержит еще и движок, который умеет применять RQL-запрос к массиву объектов.
Оригинальная реализация RQL на JavaScript есть в npmjs: https://www.npmjs.com/package/rql
Реализация с добавленной нами функциональностью также доступна через npm: https://www.npmjs.com/package/aps-rql