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 OR between predicates inside the block.
  • A predicates defined in the block could be another AND or OR grouping, containing additional predicates with another usage of the and or 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 AND between predicates inside the block.
  • A predicate defined in the block could be another AND or OR grouping, containing additional predicates with another usage of the and or 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 compare or between.
  • Another Boolean grouping by calling the or or 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 or1 or and1. You cannot call the variable or or and because those words are language keywords. Add a digit or other unique identifier to the words or or and.
Name with specific semantic meaning
For example, use carColors for 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 OR clauses 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 Collection that contains the color values. You can use any class that implements Collection, such as an array list or a set. Use the Collection as an argument to compareIn:

    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 union clause 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