title | perex | date | author | proofreading |
---|---|---|---|---|
Query API design |
The article introduces the basics of querying EvitaDB using its query API, including constructing queries, making
requests, and handling responses, with Java code examples.
|
15.12.2022 |
Ing. Jan Novotný |
done |
The evitaQL (evitaDB Query Language) entry point is represented by Query.java, and it looks like a Lisp flavoured language. It always starts with the name of the function, followed by a set of arguments in brackets. You can even use other functions in these arguments.
evitaQL is represented by a simple String that is parsed to an abstract syntax tree, which consists of constraints (Constraint.java encapsulated in Query.java We design the evitaQL String representation to look similar to a query defined in the Java notation.
Developers should create their queries in their code by using the static query
methods in
Query.java and then composing internal constraints from the static methods in
QueryConstraints.java. When this
class is statically imported, the Java query definition looks like the string form of the query.
There is also QueryParser.java which allows
for parsing the query from the String.
The string notation can be created anytime by calling the toString()
method on the Query.java object.
The parser supports passing values by reference copying the proven approach from a JDBC prepared statement
allowing the use of the character ?
in the query and providing an array of correctly sorted input parameters. It also supports the
so-called named queries,
which are widely used in the Spring framework, using variables in the query
with the :name
format and providing a Map with the named
input parameters.
In the opposite direction, it offers the toStringWithParameterExtraction
method on the Query.java
object which allows for the creating of the string format for evitaQL in the form of a prepared statement and extracting all
parameters in separate array.
This is an example how the query is composed and evitaDB requested. The example statically imports two classes: Query.java and QueryConstraints.java
final EvitaResponse<SealedEntity> entities = evita.queryCatalog(
"testCatalog",
session -> {
return session.query(
query(
collection(Entities.BRAND),
filterBy(
and(
primaryKey(1, 2, 3),
language(Locale.ENGLISH)
)
),
orderBy(
asc("name")
),
require(
entityBody(), attributes(), associatedData(), allPrices(), references()
)
),
SealedEntity.class
);
}
);
The query can also contain "dirty" parts - i.e. null constraints and unnecessary parts:
final EvitaResponse<SealedEntity> entities = evita.queryCatalog(
"testCatalog",
session -> {
return session.query(
query(
collection(Entities.BRAND),
filterBy(
and(
primaryKey(1, 2, 3),
locale != null ? language(Locale.ENGLISH) : null
)
),
orderBy(
asc("name")
),
require(
entityBody(), attributes(), associatedData(), allPrices(), references()
)
),
SealedEntity.class
);
}
);
The query is automatically cleaned and unnecessary constraints are purged before being processed by the evitaDB engine.
There are several handy visitors (more will be added) that allow you to work with the query. They are placed in the package visitor, and some have quick methods in the QueryUtils.java class.
The query can be "pretty-printed" by using the prettyPrint
method on the Query.java class.