Using Boolean algebra to combine sets of predicates
You can use Boolean
algebra to combine predicates with logical AND and OR. You use the and
and or methods on queries,
tables, and restrictions. The and
and or methods modify
the SQL query and add a clause to the query. To combine predicates, you
use Gosu blocks, which are functions that you define in-line within another
function.
Predicate linking mode
The default behavior of
a new query is to use an implicit logical AND between its predicates. This
behavior is known as a predicate linking mode of AND. The way that you apply and and or methods to a query can change
the linking mode of a new series of predicates.
The and
and or methods change
only the linking mode of the predicates that are defined in the block
that you pass to the method. The and
and or methods do not
change the linking mode of existing predicates. For example, if you apply
multiple or methods directly
to a query, the OR predicates
are joined by an AND.
The or method has the following effect on the predicate linking mode of a query:
- To existing restrictions, add one parenthetical phrase.
- Link the new parenthetical phrase to previous restrictions in the current linking mode.
- The block passed to the
or method includes a series
of predicates. Use a predicate linking mode of
ORbetween predicates inside the block. - A predicates defined in
the block could be another
ANDorORgrouping, containing additional predicates with another usage of theandor or methods.
The and method has the following effect on the predicate linking mode of a query:
- To existing restrictions, add one parenthetical phrase.
- Link the new parenthetical phrase to previous restrictions in the current linking mode.
- The block passed to the
and method includes a
series of predicates. Use a predicate linking mode of
ANDbetween predicates inside the block. - A predicate defined in the block could be another
ANDorORgrouping, containing additional predicates with another usage of theandor or methods.
Syntax of Boolean algebra methods for predicates
The syntax of the or method is:
query.or( \ OR_GROUPING_VAR -> {
OR_GROUPING_VAR.PredicateOrBooleanGrouping(...)
OR_GROUPING_VAR.PredicateOrBooleanGrouping(...)
[...]
}
The syntax of the and method is:
query.and( \ AND_GROUPING_VAR -> {
AND_GROUPING_VAR.PredicateOrBooleanGrouping(...)
AND_GROUPING_VAR.PredicateOrBooleanGrouping(...)
[...]
}
Each use of PredicateOrBooleanGrouping could be either:
- A predicate method such as
compareorbetween. - Another Boolean grouping
by calling the
oror and method.
Within the block, you call the predicate and Boolean grouping methods on the argument that you pass to the block. Do not call the predicate and Boolean grouping methods on the original query.
In the syntax specifications, OR_GROUPING_VAR and
AND_GROUPING_VAR
refer to a grouping variable name that identifies the OR or AND link mode in each peer group
of predicates. Guidewire recommends using a name for the block parameter
variable that indicates one of the following:
- Name describes the linking mode
- Use a variable name that specifies the linking mode between predicates in that group,
such as
or1orand1. You cannot call the variableororandbecause those words are language keywords. Add a digit or other unique identifier to the wordsororand. - Name with specific semantic meaning
- For example, use
carColorsfor a section that checks for car colors.
Combining AND and OR groupings
You can combine and populate AND and OR groupings with any of the following:
- Predicate methods
- Database functions
- Subselect operations
If your query consists of a large number of predicates
linked by OR clauses,
the following alternative approaches might provide better performance
in production, depending on your data:
- If the
ORclauses all test a single property and all of the values are non-null, rewrite and collapse the tests into a single comparison predicate using the compareIn method, which takes a list of non-null values.For example, if your query checks a property for a color value for matching any one of 30 color values, create a
Collectionthat contains the color values. You can use any class that implementsCollection, such as an array list or a set. Use theCollectionas an argument tocompareIn:var lastNamesArrayList = {"Smith", "Applegate"} var query = Query.make(Person) query.compareIn(Person.LASTNAME_PROP.get(), lastNamesArrayList) // Fetch the data with a for loop. var result = query.select() for (person in result) { print (person) } - Consider creating multiple subqueries
and using a
unionclause to combine subqueries.
Consider trying your query with both approaches, and then test production performance with a large number of records.
Chaining inside AND and OR groupings
Typical predicate definitions use a pattern
that uses one line of code for each predicate in the block. Using or in the name of the Gosu block
variable more closely matches an English construction that describes
the final output because an OR
clause separates the predicates. Consider using the pattern in the following
example, and avoid chaining the predicates together.
var query = Query.make(Person)
query.or( \ or1 -> {
or1.compare(Person#CreateTime, GreaterThanOrEquals,
DateUtil.addBusinessDays(DateUtil.currentDate(), -10))
or1.compare(Person#LastName, Equals, "Newton")
or1.compare(Person#FirstName, Equals, "Ray")
})
In theory, you could use method chaining to use a single line of code, rather than using three separate lines. In this case, chaining might make the code harder to understand.
var query = Query.make(Person)
query.or( \ or1 -> {
or1.compare(Person#CreateTime, GreaterThanOrEquals, DateUtil.addBusinessDays(DateUtil.currentDate(),
-10)).compare(Person#LastName, Equals, "Newton").compare(Person#FirstName, Equals, "Ray")
})Examples
For example, the following Gosu code links
three predicates together with logical OR.
The query returns rows if any of the three predicates are true for that
row.
var query = Query.make(Person)
// Find rows with creation date in the last 10 business days, last name of Newton, or first name of Ray
query.or( \ or1 -> {
or1.compare(Person#CreateTime, GreaterThanOrEquals,
DateUtil.addBusinessDays(DateUtil.currentDate(), -10))
or1.compare(Person#LastName, Equals, "Newton")
or1.compare(Person#FirstName, Equals, "Ray")
})
For example, the following Gosu code links three predicates
together with logical AND.
The query returns rows if all three predicates are true for that row.
var query = Query.make(Person)
// Find rows with last name of Newton, first name of Ray, and creation date more than 14 days ago
query.and( \ and1 -> {
and1.compare(Person#LastName, Equals, "Newton")
and1.compare(Person#FirstName, Equals, "Ray")
and1.compare(Person#CreateTime, LessThanOrEquals, DateUtil.addDays(DateUtil.currentDate(), -14))
})
This code is functionally equivalent to simple linking
of predicates, because the default linking mode is AND. The following Gosu code shows
the use of predicate linking to achieve the same query.
var query = Query.make(Person)
query.compare(Person#LastName, Equals, "Newton")
query.compare(Person#FirstName, Equals, "Ray")
query.compare(Person#CreateTime, LessThanOrEquals, DateUtil.addDays(DateUtil.currentDate(), -14))
The power of the query building system is the ability
to combine AND and OR groupings. For example, suppose
we need to represent the following pseudo-code query predicates:
(CreateTime < 10 business days ago) OR ( (LastName = "Newton") AND (FirstName = "Ray") )The following code represents this pseudo-code query by using Gosu query builders:
query.or( \ or1 -> {
or1.compare(Person#CreateTime, LessThanOrEquals,
DateUtil.addBusinessDays(DateUtil.currentDate(), -10))
or1.and(\ and1 -> {
and1.compare(Person#LastName, Equals, "Newton")
and1.compare(Person#FirstName, Equals, "Ray")
})
})
The outer OR
contains two items, and the second item is an AND grouping. This structure directly
matches the structure of the parentheses in the pseudo-code.
Similarly, suppose we need to represent the following pseudo-code query predicates:
( (WrittenDate < Today - 90 days) OR NOT ISNULL(CancellationDate) )
AND
( (BaseState = "FR") OR Locked )
The following code represents this pseudo-code using Gosu query builders:
query.or( \ or1 -> {
or1.compare(DBFunction.DateFromTimestamp(or1.getColumnRef("WrittenDate")), LessThan,
DateUtil.addDays(DateUtil.currentDate(), -90))
or1.compare(PolicyPeriod#CancellationDate, NotEquals, Null)
})
query.or( \ or2 -> {
or2.compare(PolicyPeriod#BaseState, Equals, Jurisdiction.TC_FR)
or2.compare(PolicyPeriod#Locked, Equals, true)
})
Each OR
contains two items, and the two OR
items are combined using the default predicate linking mode of AND. This structure directly matches
the structure of the parentheses in the pseudo-code.
See also
