I have got followed structure:
public class Proposal {
private final List<Product> products;
private final List<Customer> customers;
}
public class Customer {
private String id;
private String country;
}
public class Product {
private String customerId;
private String country;
private String type;
}
the 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'
Based on that I prepared a rule but it does not work as it should:
//rule body
Proposal($products: products, $customers: customers)
$productsToChecks : Product(customerId != "21") && type not in ("A", "B") from $products
//first condition to check if there is any applicable case:
exist(Product(customerId != "21") && type not in ("A", "B") from $products) and
(
// check if there is a customer who can use this product
forall (
Product($customerId: customerId, $country: country) from $productsToChecks
Customer(id == $customerId || (country == null && $country == "US"))
)
)
Thank you for any help or advice
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:
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