I have an object graph that I am trying to generate Fulfillment object from in Drools. Specifically, Fulfillment objects represent a rule that is either satisfied, or unsatisfied. My object graph looks like the following:
Users ---> many Requirements --> Event
`--> many Records ----^
Records can fulfill Requirements if they both point at the same Event. This produces a Fulfillment object in Drools.
A reduce down rule to produce Fulfillments is the following:
rule "fulfils"
when
$u : User()
$rec : Record() from $u.records
$r : Requirement(event contains $rec.event) from $u.requirements
then
insertLogical( new Fulfillment($u, $rec, $r, true));
System.out.println("Inserting logical");
end
rule "unfulfils"
when
$u : User()
$rec : Record() from $u.records
$r : Requirement(event not contains $rec.event) from $u.requirements
then
insertLogical( new Fulfillment($u, $rec, $r, false));
System.out.println("Inserting logical");
end
query "fulfillment"
$fulfillment : Fulfillment()
end
The problem I run into here is if the user has no records, there is no Fulfillment inserted for the requirement. I believe this is because there is no Record() to search on to satisfy my graph.
Is there a way to use the records without requiring more than zero to exist?
Also, do I need two rules here to insert both true and false Fulfillments or is there a better way to do this?
Edit
Another problem I am facing with these rules is the Requirement(event contains $rec.event)
does not accomplish the task of finding if any records satisfy the given collection of events. Is there a better way to find if there exists an overlap between the many record's single events, and the single requirements multiple events?
Another Edit
Here's another approach I thought up. Instead of inserting Fulfillments if a requirement/record pair is not found, why not just insertLogical Fullfillments for all Requirements that have no matching positive Fullfillment:
rule "unfulfils"
when
$u : User()
$r : Requirement() from $u.requirements
not(Fulfillment(user == $u, requirement == $r, fulfilled == true))
then
insertLogical( new Fulfillment($u, null, $r, false));
System.out.println("Inserting logical");
end
query "fulfillment"
$fulfillment : Fulfillment()
end
This takes care of the issue of comparing the overlap of two collections, and the case where a user has no records. (Would appreciate some validation on this).
Using 2 different rules for your situation is a common pattern. It makes your rule base easier to read (and in a way to maintain too). Regarding your question about no Record(), I think you could write something like this (If I understood your question correctly):
rule "unfulfils because of no Record"
when
$u : User(records == null || records.empty == true) //A user without records
$r : Requirement() from $u.requirements // but with Requirements
then
//You don't have a record to set in your Fulfillment object
insertLogical( new Fulfillment($u, $rec, null, false));
System.out.println("Inserting logical");
end