📜 ⬆️ ⬇️

What is RQL

Imagine that you have a data warehouse with a REST interface. Let it contains information about books and you want to display a list of all books. You can make the method of "books", which will return us a list of books. But when the list is displayed, there is usually a padjina or lazy loading of data, and still wants 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 we receive without transferring some of the fields. All this information should be able to understand almost any method of obtaining a list of objects, since lists are displayed using a special widget. And this is where Resource Query Language comes to the rescue.

Resource Query Language (RQL) is a query language designed to be used in URIs when working with object-like data structures. Using RQL, a client can request from the server a list of objects that comply with certain rules, i.e., in essence, this is the syntax that describes how to request data. For example, a query that selects all books of authorship by Perumov can be written as eq(author,) or in the usual URL format: author= .

RQL can be considered, basically, as a set of nested operators, each of which has a set of arguments. It is designed for a very simple but extensible grammar that 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 scripts


First we analyze typical scenarios. For better understanding, we will compare with similar commands in MongoDB.

Suppose we have a list of books:

 [ { title: " ", year: 1993, series: " " }, { title: " ", year: 1993, series: " " }, { title: " ", year: 1995, series: " " }, { title: "  ", year: 1995, series: " " } ] 

Let's display all the 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 us three books.

Now a more complex query: we need to bring 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" } } 

The nested object with the translations key is defined here. And to find all the books translated into English, we need to use a dot.

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 show it page by page.

In MongoDB we can get the second dozen records as follows:

 db.users.find().skip(10).limit(10) 

In RQL:

 limit(10,10) 

But show little by page. 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:
FunctionDescription
in (<propyrty>, <array-of-values>)Selects objects whose value is
The specified property is included in the specified array of properties.

Example:
in(name,(Silver,Gold))
out (<propyrty>, <array-of-values>)Selects objects for which the value of the specified property is not included in the specified array of properties.

Example:
out(name,(Platinum,Gold))
limit (<start>, <number>)Returns the specified number
(number) of objects starting from a certain ( start ) position.

Example:
limit(0,2)
sort (<list of properties with + or - prefix>)Sorts the list of objects by 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 sort order is determined by the prefix: + - ascending, - - descending.

Example:
sort(+memory,-diskspace)
select (<list offf attributes>)Cuts each object to the set of properties specified in the arguments.

Example:
select(name,user)
values ​​(<property>)Returns a set of values ​​from the specified field of all objects.

Example:
values(ve.name)
count ()Returns the number of records.

Example:
in(name,(Silver,Gold))&count()
max (<property?>)Returns the maximum value from the specified field of all objects.

Example:
max(ve.memory)
min (<property?>)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 feature has been added to RQL:
FunctionDescription
like (<property>, <pattern>)Searches for a given pattern (pattern) in a given property (property). This
the function is similar to the SQL LIKE operator, although it uses the * symbol instead of % . To determine the character * itself in a pattern, it must be percent-coded, that is, you must write %2A instead of * , see examples. In addition, in the pattern, you can use the symbol ? denoting that any character in this position is valid.

Examples:
like(firstName,Jo*)
like(firstName,*ohn)
like(firstName,*oh*)
like(firstName,Joh?)

And three more APS-specific functions:
FunctionDescription
implementing (<bas-type>)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)
composing (<derived-type>)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)
linkedWith (<resource ID>)Returns a list of resources that are associated with the resource whose ID is specified as an argument. The APS controller searches for all resource references, including internal system references. For example, the admin / owner / referrer actor with access to the resource will also be considered a “bound” resource.

Examples:
linkedWith(220aa29a-4ff4-460b-963d-f4a3ba093a0a)

implementing(http://aps-standard.org/types/core/user/service/1.0), linkedWith(220aa29a-4ff4-460b-963d-f4a3ba093a0a)

Logical operators


Logical operators allow, through Boolean logic, to combine two or more query functions. All standard logical operators have short aliases.
OperatorAliasExamples
and (<query>, <query>, ...)&
,
and (limit(0,2),like(name,*L*))

Value
Selects the first two sentences whose names match the case insensitive pattern *L*
or (<query>, <query>, ...)|
;
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 is Silver or Gold .

In APS technology, a new logical negation operator has also been added to RQL:
OperatorExamples
not (<query>)not(like(name,*free*))

Value
Selects all offers, except those whose name matches
Habr and HotTimes - RQL pattern *free* .

Note

  1. The and operator is an implicit top-level RQL operator. For example, the expression http://hosting.com?and(arg1,arg2,arg3) equivalent to http://hosting.com?arg1,arg2,arg3 .
  2. Operator and priority is higher than or. Therefore, when using aliases, you need to enclose the combined queries in parentheses, thereby determining the necessary processing order. For example, implementing(<typ>),(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 .
OperatorAliasExamples
eq (<propyrty>, <valu>)= eq =eq(aps.status,aps:ready)
aps.status=eq=aps:ready


Value
Selects all objects whose aps.status is set to aps:ready .
ne (<propyrty>, <valu>)= ne =ne(aps.status,aps:ready)
aps.status=ne=aps:ready


Value
Selects all objects whose aps.status is set to aps:ready .
gt (<propyrty>, <valu>)= gt =implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.memory = gt = 1024)

Value
Selects all offers (offers) that provide hardware.memory more than 1024.
ge (<propyrty>, <valu>>)= ge =implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.memory = ge = 1024)

Value
Selects all offers (offers) providing hardware.memory greater than or equal to 1024.
lt (<propyrty>, <valu>)= lt =implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.CPU.number = lt = 16)

Value
Selects all offers (offers) providing hardware.CPU.number less than 16.
le (<propyrty>, <valua>)= le =implementing (http://aps-standard.org/samples/user-mgmt/offer), hardware.CPU.number = le = 16)

Value
Selects all offers (offers) providing hardware.CPU.number less than or equal to 16.

String types are compared in lexicographical order .

Meanings


Query functions and comparison operators may contain the following values:


Value functions are functions that return special values ​​like null , true , false or an empty string value. They all apply to certain types of data.
Function valueApplicable TypesDescriptionsExamples
null ()Any typeSet if the value is nullname=eq=null()
true ()
false ()
BooleanSet if true or falsedisabled=eq=false()
empty ()StringSet 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 implementations of RQL parsers in various programming languages.

The JavaScript implementation, in addition to the parser, also contains an engine that can apply an RQL query to an array of objects.

The original implementation of RQL in JavaScript is in npmjs: https://www.npmjs.com/package/rql

The implementation with the functionality added by us is also available via npm: https://www.npmjs.com/package/aps-rql

Source: https://habr.com/ru/post/331774/


All Articles