Query Engine

download       view javadocs

Introduction:

The Query Object Framework, provides a set of Java Language utilities for performing generic structured complex queries on a set of data held by a List of java objects. This framework is unique in that it does NOT require SQL or any database at all to perform the query. Thus, it allows programmers to add query support to their applications without having to hook into an SQL Database.

Typically, if you have an application, and you want to search objects depending on field value(s), you will need the ability to perform queries in order to get the data you need.

The idea behind Query Object Framework is to provide a generic framework so that any query can be executed. Normally, this is possible only if you use a database that supports SQL, and then only if you deeply embed the database into your application. QOF provides simpler, more natural way to work with objects.

Field Name

One of the simplest objects to define, it only requires a persistent data member name to be initialized via the constructor

Variable data.

Variable data refers to the runtime value of a data member. Static information such as the name and type of the field/method, number, and class of the parameters in case of a method, and the application object’s class is enough to retrieve its value at runtime for a given object, using Java reflection APIs.

Operators

Though Java language defines a fixed number of operators that operate on primitive data types, developers have the discretion of providing as many (or as few) and as complex (or as simple) operators as desired for writing program logic at runtime. An operator takes a fixed number of operands and produces a Boolean result. A Java class written to provide a primitive operator takes the required number of operands (i.e., data) of appropriate type as arguments in its constructor.

Operators are based on interface Operator which takes a Object and returns a boolean if operation succeeds.

public interface Operator {

    public boolean getResult(Object object);

}

Operator has two subclasses. Relational Operator and Logical Operator.

Relational Operator takes a fieldname and fixed data (a Comparable object since we need to invoke compare method to compare two values for an operator). Relational operator has four subclasses namely GreaterThan, LesserThan, Equals and NotEquals.

public abstract class RelationalOperator implements Operator {

	public  RelationalOperator(String fieldName, Comparable fixedData) {    }

	public  RelationalOperator(String fieldName, boolean booleanFixedData) {    }
}

Operator Class Name Description
= Equals Expression is True if the value in the specified fieldName equals the specified value in the expression
!= NotEquals(String fieldName, Comparable value) Expression is True if the value in the specified fieldName does not equal the specified value
> GreaterThan(String fieldName, Comparable value) Expression is True if the value in the specified fieldName is less than the specified value
< LesserThan(String fieldName, Comparable value) Expression is True if the value in the specified fieldName is greater than the specified value

Logical operator takes two Operators as argument since it can operate on Relational or Logical Operators to get result. Logical operators has two subclasses namely And and Or.

public abstract class LogicalOperator implements Operator {

    public  LogicalOperator(Operator lhsOperator, Operator rhsOperator) {    }
}

QueryList

It is a collection, which extends java.util.ArrayList, and has the following additional utility methods:

Filter

Can be used to filter a collection using operators as already described above.

Sort

Can be used to sort a collection based on the property / field of the bean. Sorting can be done on multiple fields as well.

Sum

Can be used to get sum of a property / field of beans in the collection.
Note:the field type should be numeric type (i.e. byte, short, int, long, float, double)

Example

The following example illustrates how expressions (Operators) can be constructed at runtime.
Let us have a simple bean (Employee), which has the following properties.

public class Employee {

	public boolean permanent;
	public int salary;
	public String name;
	public int age;
	public boolean married;
	....
}

Add Employee bean instances to QueryList. If we need to get all employee whose age is above 30, build the operator as follows :
GreaterThan gtAge = new GreaterThan("age", 30);
To execute the query in Querylist we would call:
queryList.filter(gtAge);
which returns a Querylist instance containing all employee beans satisfying the above condition.
where queryList is an instance of Querylist containing Employee beans.
Using these operators we can build more complex queries. Say for example, we need to retrieve the details for employees above age 30 and salary greater than 10000 or married and permanent employees.
	GreaterThan gtAge = new GreaterThan("age", 30);
	GreaterThan gtSalary = new GreaterThan("salary", 10000);
	Equals eqMarried = new Equals("married", true);
	Equals eqPermanent = new Equals("permanent", true);
	And MandP = new And(eqMarried, eqPermanent);
	And ageAndSal = new And(gtAge, gtSalary);
	Or or = new Or(MandP, ageAndSal);
The final operator would be:
(e.married && e.permanent) || ((e.age > 30) && (e.salary > 10000))