What is RQL
Imagine you have a data warehouse with a REST interface. Let it contain information about books and you want to list all the books. You can make a “books” method that will return us a list of books. But when displaying a list, there is usually pagination or lazy loading of data, and still wants to use it to filter and sort the data. When we add support for mobile devices, we still have a need to somehow limit the amount of data received without passing some of the fields. Almost any method of obtaining a list of objects should be able to understand all this information. lists are displayed using a special widget. And here the Resource Query Language comes to the rescue.
Resource Query Language (RQL) is a query language designed for use in URIs when working with object-like data structures. Using RQL, the client can request from the server a list of objects that comply with certain rules, i.e., in fact, this is the syntax that describes how to request data. For example, the query selects all books Perumova attribution can be written as
RQL can be considered mainly as a set of nested operators, each of which has many arguments. It is designed for a very simple, but extensible grammar, which can be used in a valid URL request.
An RQL expression contains query functions or comparison operators connected by logical operators.
First, we will analyze typical scenarios. For a better understanding, we will compare with similar commands in MongoDB.
Let us have a list of books:
List all books from the Ring of Darkness series. In MongoDB, we would do it like this:
in RQL, it will look like this:
or
Such a request will return three books to us.
Now a more complex query: we need to display all the books of the Ring of Darkness series published in 1995.
In MongoDB:
In RQL:
Previous queries applied to simple objects. But documents can be very complex in structure. For example, add a new book to our library:
A nested object with a key is defined here
In MongoDB:
In RQL:
Over time, our library has grown. The list of books does not fit on the screen and we decided to display it page by page.
In MongoDB, we can get the second ten records as follows:
In RQL:
But showing page by page is not enough. I also want to sort the data.
In MongoDB, this will be:
In RQL:
Basic functions of the standard:
More existing operators can be found in the official documentation .
In APS technology, a new function has been added in RQL:
And three more APS-specific features:
Boolean operators allow two or more query functions to be combined using Boolean logic. All standard logical operators have short aliases.
In APS technology, RQL also added a new logical negation operator:
Note
The comparison operator is used to filter objects by comparing one of their properties with a given value .
String types are compared in lexicographic order .
Query functions and comparison operators can contain the following values:
Function values - are functions that return special values such as
There are a large number of RQL parser implementations in various programming languages.
The implementation in JavaScript, in addition to the parser, also contains an engine that can apply an RQL query to an array of objects.
The original JavaScript RQL implementation is in npmjs: https://www.npmjs.com/package/rql
An implementation with the functionality we added is also available through npm: https://www.npmjs.com/package/aps-rql
Resource Query Language (RQL) is a query language designed for use in URIs when working with object-like data structures. Using RQL, the client can request from the server a list of objects that comply with certain rules, i.e., in fact, this is the syntax that describes how to request data. For example, the query selects all books Perumova attribution can be written as
eq(author,Перумов)or in a conventional URL format author=Перумов. RQL can be considered mainly as a set of nested operators, each of which has many arguments. It is designed for a very simple, but extensible grammar, which can be used in a valid URL request.
How to use RQL
An RQL expression contains query functions or comparison operators connected by logical operators.
Typical Scenarios
First, we will analyze typical scenarios. For a better understanding, we will compare with similar commands in MongoDB.
Let us have a list of books:
[
{ title: "Эльфийский клинок", year: 1993, series: "Кольцо тьмы" },
{ title: "Чёрное копьё", year: 1993, series: "Кольцо тьмы" },
{ title: "Адамант Хенны", year: 1995, series: "Кольцо тьмы" },
{ title: "Воин Великой Тьмы", year: 1995, series: "Летописи Хьёрварда" }
]List all books from the Ring of Darkness series. In MongoDB, we would do it like this:
db.users.find({series: "Кольцо тьмы"})in RQL, it will look like this:
eq(series, "Кольцо тьмы")or
series="Кольцо тьмы"Such a request will return three books to us.
Now a more complex query: we need to display all the books of the Ring of Darkness series published in 1995.
In MongoDB:
db.users.find({series: "Кольцо тьмы", year: 1995})In RQL:
eq(series, "Кольцо тьмы"),eq(year, 1995)Previous queries applied to simple objects. But documents can be very complex in structure. For example, add a new book to our library:
{ title: "Воин Великой Тьмы", year: 1995, series: "Летописи Хьёрварда", translations: { language: "English", title: "Godsdoom" } }A nested object with a key is defined here
translations. And to find all the books translated into English, we need to use a period. In MongoDB:
db.users.find({"translations.language": "English"})In RQL:
eq(translations.language, "English")Over time, our library has grown. The list of books does not fit on the screen and we decided to display it page by page.
In MongoDB, we can get the second ten records as follows:
db.users.find().skip(10).limit(10)In RQL:
limit(10,10)But showing page by page is not enough. I also want to sort the data.
In MongoDB, this will be:
db.users.find().sort({title: 1})In RQL:
sort(+title) Functions
Basic functions of the standard:
| Function | Description |
|---|---|
| Selects objects for which the value of the specified property is included in the specified array of properties. Example: in(name,(Silver,Gold)) | |
| Selects objects for which the value of the specified property is not included in the specified array of properties. Example: out(name,(Platinum,Gold)) | |
| Returns the specified amount (number) of objects beginning with specific ( start ) position. Example: limit(0,2) | |
sort (
| Sorts the list of objects by the specified properties (the number of properties is unlimited). First, the list is sorted by the first of the specified properties, then by the second, and so on. The sorting order is determined by the prefix: + - ascending, - - descending. Example: sort(+memory,-diskspace) |
| Trims each object to a set of properties defined in arguments. Example: select(name,user) |
| Returns a set of values from the specified field of all objects. Example: values(ve.name) | |
| Returns the number of records. Example: in(name,(Silver,Gold))&count() | |
| Returns the maximum value from the specified field of all objects. Example: max(ve.memory) | |
| Returns the minimum value from the specified field of all objects. Example: min(ve.memory) |
More existing operators can be found in the official documentation .
In APS technology, a new function has been added in RQL:
| Function | Description |
|---|---|
) | Searches for a given pattern in a given property. This function is similar to the SQL LIKE statement, although it uses a character *instead %. To determine the symbol itself in the pattern *, it must be percent-encoded, that is, it must be written %2Ainstead *, see examples. In addition, a symbol can be used in the pattern to ?indicate that any symbol in this position is valid. Examples: like(firstName,Jo*) |
And three more APS-specific features:
| Function | Description |
|---|---|
| Returns a list of objects (resources and types) that implement the base type and include the base type itself. Example: implementing (http://aps-standard.org/samples/user-mgmt/offer/1.0) | |
| Returns a list of types that are implemented by the derived type, including the derived type itself. Example: composing(http://aps-standard.org/samples/user-mgmt/offer/1.0) | |
| Returns a list of resources that are linked by the resource whose ID is specified as an argument. The APS controller looks for all links to resources, including internal system links. For example, an admin / owner / referrer actor that has access to a resource will also be considered a “linked” resource. Examples: linkedWith(220aa29a-4ff4-460b-963d-f4a3ba093a0a) |
Logical operators
Boolean operators allow two or more query functions to be combined using Boolean logic. All standard logical operators have short aliases.
| Operator | Alias | Examples |
|---|---|---|
| & , | and (limit(0,2),like(name,*L*))Value Selects the first two sentences whose names match a case-insensitive pattern. *L* | |
| or ( | | ; | or(like(description,*free*),in(name,(Silver,Gold)))Value Selects all sentences whose descriptions correspond to the pattern *free*, as well as those whose name Silver or Gold. |
In APS technology, RQL also added a new logical negation operator:
| Operator | Examples |
|---|---|
| not ( | not(like(name,*free*))Value Selects all sentences, with the exception of those whose name corresponds to the Habr and Gictimes - RQL pattern *free*. |
Note
- The operator
andis an implicit top-level RQL operator. For example, the expression ishttp://hosting.com?and(arg1,arg2,arg3)equivalenthttp://hosting.com?arg1,arg2,arg3. - The and operator has higher precedence than or. Therefore, when using aliases, you need to enclose the combined queries in parentheses, thereby determining the necessary processing order. Eg .
implementing(),(prop1=eq=1|prop2=ge=2)
Comparison operators
The comparison operator is used to filter objects by comparing one of their properties with a given value .
| Operator | Alias | Examples |
|---|---|---|
| = eq = | eq(aps.status,aps:ready)Value Selects all objects whose aps.statusvalue is aps:ready. | |
| = ne = | ne(aps.status,aps:ready)Value Selects all objects whose aps.statusvalue is aps:ready. | |
| = gt = | implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.memory = gt = 1024) Value Selects all offers offering hardware.memorymore than 1024. | |
| = ge = | implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.memory = ge = 1024) Value Selects all offers offering hardware.memorymore than or equal to 1024. | |
| = lt = | implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.CPU.number = lt = 16) Value Selects all offers offering hardware.CPU.numberless than 16. | |
| = le = | implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.CPU.number = le = 16) Value Selects all offers offering hardware.CPU.numberless than or equal to 16. |
String types are compared in lexicographic order .
Values
Query functions and comparison operators can contain the following values:
- String (using URL encoding)
- The numbers
- Dates (in ISO UTC format without a colon)
- Booleans
- Value Functions
Function values - are functions that return special values such as
null, true, false or an empty string. All of them are applicable to certain types of data.| Value function | Applicable Types | Descriptions | Examples |
|---|---|---|---|
| null () | Any type | Set if value null | name=eq=null() |
| true () false () | Booleans | Set if the value true orfalse | disabled=eq=false() |
| empty () | String | Set if the string value is empty (not null, but does not contain any characters) | addressPostal.extendedAddress=eq=empty() |
Using
There are a large number of RQL parser implementations in various programming languages.
The implementation in JavaScript, in addition to the parser, also contains an engine that can apply an RQL query to an array of objects.
The original JavaScript RQL implementation is in npmjs: https://www.npmjs.com/package/rql
An implementation with the functionality we added is also available through npm: https://www.npmjs.com/package/aps-rql