Sometimes the capabilities of regular SODA-queries is not enough. In such cases you can add evaluations to the SODA-query. A evaluation is a piece of code which runs against objects.
To use a evaluation, you need to pass an instance of the Evaluation-interface as a constrain. db4o will call the match-method of that interface. Implement the match-method of the Evaluation-interface. In the match-method you can get the candidate-object and the object-container. Compare the object and when it matches, pass true to the include-method. Otherwise pass false.
While SODA evaluations are extremely powerful they are also slow. In order to run the evaluation the objects need to be instantiated from the database and then processed by the evaluator. This means that you should use evaluations only when there's no other possibility.
Here's an example for a simple evaluation. This evaluation filters pilots by the age and picks only pilots with an odd-number as age.
First we need to create the evaluation class:
class OnlyOddAge implements Evaluation { public void evaluate(Candidate candidate) { Pilot pilot = (Pilot) candidate.getObject(); candidate.include(pilot.getAge()%2!=0); } }
After that, you can use the evaluation in the SODA-query. An evaluation is added as a regular constrain.
final Query query = container.query(); query.constrain(Pilot.class); query.constrain(new OnlyOddAge()); ObjectSet result = query.execute();
It's also possible to use the evaluation on a certain field. For this you descend into the field on which the evaluation should be applied. After that, specify the evaluation as a constrain on that field.
final Query query = container.query(); query.constrain(Car.class); query.descend("pilot").constrain(new OnlyOddAge()); ObjectSet result = query.execute();
Evaluation also allow you to add very specific additional query capabilities. On of the most useful ones is regular expressions. First create a regular expression evaluation:
class RegexConstrain implements Evaluation { private final Pattern pattern; public RegexConstrain(String pattern) { this.pattern = Pattern.compile(pattern); } public void evaluate(Candidate candidate) { String stringValue = (String) candidate.getObject(); candidate.include(pattern.matcher(stringValue).matches()); } }
After that you can use it on any string field:
final Query query = container.query(); query.constrain(Pilot.class); query.descend("name").constrain(new RegexConstrain("J.*nn.*")); ObjectSet result = query.execute();