Introducing Quaere - Language integrated queryies for Java
Earlier today, I unveiled the Quaere project during my talk at the JavaZone conference.
Quaere is an internal domain specific language that adds a querying syntax reminiscent of SQL to Java applications. The language is modeled with basis in Microsoft’s Language Integrated Query (LINQ) project, which adds similar capabilities to a range of Microsoft .NET languages.
The Quaere project allows users to use an internal DSL to filter, enumerate and create projections over a number of collections and other queryable resources using a common, expressive syntax.
Features
The Quaere DSL is very flexible and it lets you perform a wide range of queries against any data structure that is an array, or implements the java.lang.Iterable or the org.quaere.Queryable interface. Below is an overview of the querying and other features available through the DSL interface, the underlying query expression model and query engine. See the examples section to gain an understanding of how these features are used.
- Ability to perform queries against arrays or data structure implementing the Iterable interface.
- An internal DSL (based on static imports and fluent interfaces) that lets you integrate the query language with regular Java code. No preprocessing or code generation steps are required to use the DSL, simply add a reference to the quaere.jar file (and its dependencies).
- A large number of querying operators including restriction, selection, projection, set, partitioning, grouping, ordering, quantification, aggregation and conversion operators.
- Support for lambda expressions.
- The ability to dynamically define and instantiate anonymous classes.
- Many new “keywords” for Java 1.5 and later.
Examples
To import the DSL into any Java class, simply add the following import to the class:
import static org.quaere.DSL.*;
Below is an example of a simple query that selects the numbers less than five from an array of integers:
Integer[] numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0};
Iterable<Integer> lowNums =
from("n").in(numbers).
where(lt("n", 5)).
select("n");
This query uses a projection expression to select the names of all products in the array:
List<Product> products = Arrays.asList(Product.getAllProducts());
Iterable<String> productNames =
from("p").in(products).
select("p.getProductName()");
The following query creates a sequence anonymous class instances with two properties containing the upper and lower case versions of the words in an array. The classes in the upperLowerWords collection will have two strongly typed JavaBean properties:
String[] words = {"aPPLE", "BlUeBeRrY", "cHeRry"};
Iterable<Variant> upperLowerWords =
from("w").in(words).
select(
create(
property("upper", "w.toUpperCase()"),
property("lower", "w.toLowerCase()")
)
);
The following query uses a compound from clause to select all pairs of numbers from two arrays such that the number from numbersA is less than the number from numbersB:
Integer[] numbersA = {0, 2, 4, 5, 6, 8, 9};
Integer[] numbersB = {1, 3, 5, 7, 8};
Iterable<Variant> pairs =
from("a").in(numbersA).
from("b").in(numbersB).
where(lt("a", "b")).
select(
create(
property("a"),
property("b")
)
);
For more examples take a look at the scenario test cases in the snapshot. The project has passing tests for almost all of the examples in Microsoft’s LINQ showcase applications.
License and Contributions
The project is licensed under the Apache 2.0 License. The project is not yet hosted by any open source community, and is therefore only available as a downloadable snapshot. The snapshot is available here.