What's The Difference Between JoSQL & Quaere?

Published 18 September 07 04:50 AM | andersnoras 

In the ongoing discussions at The Server Side the is some confusion if there is any difference between Quaere and JoSQL. JoSQL, aka SQL for Java Objects, is a great framework which allows developers to run SQL like queries against collections of POJOs. At first glance, this is very similar to Quaere for Objects, with the only difference being the implementation of the querying language. Quaere uses fluent interface and static imports to create the illusion of having language extension akin to Microsoft’s C# 3.0 LINQ queries. JoSQL on the other hand uses strings to define queries.

A popular example of the what you can achieve with JoSQL is an example that selects a list of file names and sizes ordered by these properties. Below you can see the JoSQL code to perform this query.

// Get a list of java.io.File objects.
List myObjs = getMyObjects ();

// Create a new Query.
Query q = new Query ();

// Parse the SQL you are going to use, it is assumed here that
// "myObjs" contains instances of "java.io.File".
q.parse ("SELECT name,length " +
"FROM java.io.File " +
"WHERE fileExtension (name) = :fileExt " +
"ORDER BY length DESC, name " +
"EXECUTE ON RESULTS avg (:_allobjs, length) avgLength");

// Set the bind variable "fileExt".
q.setVariable ("fileExt", "java");

// Execute the query.
QueryResults qr = q.execute (myObjs);

// Get the average length, this is a save value, the result
// of executing the call "avg (:_allobjs, length)", it is saved against
// key: "avgLength".
Map saveValues = qr.getSaveValues ();
Number avg = (Number) saveValues.get ("avgLength");

// Cycle over the results.
List res = qr.getResults ();

for (int i = 0; i < res.size (); i++)
{

// This time there is a List for each row, index 0 holds the name of
// the file that matched, index 1 holds the length.
List r = (List) res.get (i);

System.out.println ("NAME: " + r.get (0));
System.out.println ("LENGTH: " + r.get (1) + ", AVG: " + avg);

}

Below is the same query written using Quaere for Objects.

// Get a list of java.io.File objects
List<File> project = getFilesInTree(new File("/Users/anders/IdeaProjects/quaere"));

Iterable<Variant> sourceFiles=
from("f").in(project).
orderByDescending("f.length()").orderBy("f.getName()").
where("f.getName().endsWith(\"java\")").
select(
create(
property("f.getName()"),
property("f.length()")
)
);

for (Variant fileInfo: sourceFiles) {
System.out.println(String.format("Name: %s, Size: %s",fileInfo.get("name"),fileInfo.get("length")));
}

The only difference practical difference between the two example is that the JoSQL example also calculates the average file size. This is left out in the Quaere example, because there are currently some issues with some of the aggregation operators.

Naturally, I’m very biased when it comes to my opinions on Quaere, but I feel that the Quaere query has better cohesion with the “business problem” because you specify the actual list of files as the query source (the in-clause), while JoSQL uses the class name (java.io.File). To be honest, I mistook the JoSQL example for being a clever reflection example, akin to the Quaere example below, the first time I saw it.

// Find all the getters on the java.io.File class.
Iterable<Method> getters=
from("m").in(File.class.getMethods()).
where("m.getName().startsWith(\"get\")").
select("m");

Other difference is the verbosity of the query and type safety. The Quaere query is much more compact than the JoSQL query, mainly because we don’t have to bind query arguments and execute the query separately. Quaere is also type safe, mostly because it leverages generics.

However, the key difference between the two frameworks is not how you would perform the query above, but that Quaere is an language and an extensible querying model. A better way to query for files with a “.java” extension would be to use a FilenameFilter to determine whether a file is a Java source file or not, rather than loading a bunch of File objects and the applying the restriction afterwards. Because of Quaere’s extensibility mechanism (via the Queryable interface), we can create a query source that executes its queries against the file system, eliminating the need to do the IO operations outside of the query. Below is an example of what such a query would look like:

Iterable<Variant> sourceFiles=
from("f").in(new FileQuery("/Users/anders/IdeaProjects/quaere/").queryAllFilesRecursively()).
orderByDescending("f.length()").orderBy("f.name()").
where(eq("f.extension()","java")).
select(
create(
property("f.name()"),
property("f.length()")
)
);

The queryAllFilesRecursively method returns a class (FileQuery) that implements the Queryable interface, and the expression tree for the query is passed to this object, rather than Quaere for Objects as in the previous example, when the query is executed. The FileQuery query will then translate the method call expression eq(“f.extension()”,”java”) into a FilenameFilter similar to the one shown below, which the FileSystem query will then pass to the java.io.File.list(FilenameFilter) method.

FilenameFilter filter=new FilenameFilter() {
public boolean accept(File file, String name) {
return name.endsWith(".java");
}
};

This allows us to make more efficient queries against the file system than we did in the Quaere for Objects example.

The ability to seamlessly add new querying engines is one of the key features that distinguishes Quaere from other similar frameworks.

Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Enter the code you see below