You have a syntax error in your $productsToChecks
declaration:
$productsToChecks : Product(customerId != "21") && type not in ("A", "B") from $products
Both of the attributes you're checking need to be inside of the Product( ... )
part like this:
$productsToChecks: Product( customerId != "21",
type not in ("A", "B")) from $products
You repeat this error in other parts of the rule as well.
So your requirements are:
Don't check if the product type is "A" or "B" and for customer with id: 21. For any other products check if customerId match with id or if the customer country is set to null and the country on the product is set to 'US'
We can distill this to the following pseudo-code:
- When
- Product is not: (type=A or type=B) and customerId=21
- (Product customerId == Customer id) OR (Customer country == null and Product country == US)
- Then do something
Given the 'OR' in the second part, this is two rules.
The first part we need to do is find the subset of products that we care about. You can do this in a number of ways -- collect
or accumulate
are the two that immediately come to mind. Assuming that the requirements in your question are complete, collect
is more appropriate here (and simpler).
Proposal($products: products, $customers: customers)
$productSubset: List() from collect( Product( customerId != 21, type not in ("A", "B") ) from $products)
Now you can use that subset of products (which don't include the ones you need to ignore) to match your other criteria. As I mentioned, since those criteria are OR'd, they should be two distinct rules.
rule "Product customerId matches Customer id"
when
Proposal($products: products, $customers: customers)
$productSubset: List()
from collect( Product( customerId != 21, type not in ("A", "B") ) from $products)
Customer( $id: id != null ) from $customers
$product: Product( customerId == $id ) from $productSubset
then
// do something with $product
end
rule "US Product and no Customer Country"
when
Proposal($products: products, $customers: customers)
$productSubset: List()
from collect( Product( customerId != 21, type not in ("A", "B") ) from $products)
Customer( country == null ) from $customers
$product: Product( country == "US" ) from $productSubset
then
// do something with $product
end
To cut down on the duplicate code, you can pull the common conditions into a single 'parent' rule and then use the extends
keyword to create the two child rules with their distinct conditions.
I designed these rules in this way under the assumption that you want to do some action against each of the products that meets your criteria. Based on this assumption, the right hand side will trigger for each product that matches the criteria of each rule (also note that since the two rules are not exclusive, products might trigger twice if the customerId matches and the country requirements are satisfied.)
However if all you want as the result is a list of all products that meets the criteria, you can again use a function to obtain that list of products. In this case, the accumulate
function more appropriate than collect
:
rule "Get list of products for customer"
when
Proposal($products: products, $customers: customers)
$productSubset: List()
from collect( Product( customerId != 21, type not in ("A", "B") ) from $products)
Customer( $id: id != null, $country: country ) from $customers
$product: Product( customerId == $id ) from $productSubset
$customerProducts: List() from accumulate(
$p: Product((customerId == $id) || ($country == null && country == "US")) from $products,
collectList($p)
)
then
// do something with $customerProducts
end