|
List Info
Thread: How check if all the values in a collection match a criteria
|
|
| How check if all the values in a
collection match a criteria |
  Ireland |
2008-05-18 12:04:10 |
Hi,
I have these two classes:
ExpenseReport{
Collection<ExpenseDetails> expenseDetails
}
ExpenseDetails{
ExpenseReport document
ExpenseType expenseType
}
I am trying to create a rule that fires when all the
ExpenseDetails in a
ExpenseReport are of the same type:
rule "Do Not Process TAX"
when
$report: ExpenseReport($expenseDetails: expenseDetails)
forall (
ExpenseDetails(document==$report, expenseType ==
ExpenseType.TAX)
)
then
System.out.println("################ It works
##################");
insertLogical("Bypass Process");
end
For some reasons, it fires regardless that value of
ExpenseDetails.expenseType.
I just started with drools and any help i more than
welcome.
Thanks
_______________________________________________
rules-users mailing list
rules-users lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users
|
|
| Re: How check if all the values in a
collection match a criteria |

|
2008-05-18 14:30:34 |
|
Hmm, now that you mentioned, I see that our parser is limiting the forall() CE, not allowing nested "from" CEs. This is something we should fix, since the limitation is purely a parser limitation.
Anyway, for your case, the workaround is simply to use the "raw" forall-equivalence: not( A() and not( B() ) ). So try this:
rule "Do Not Process TAX" when
$report: ExpenseReport($expenseDetails: expenseDetails)
not ( $ed : ExpenseDetails() from $expenseDetails and not ( ExpenseDetails( this == $ed, expenseType == ExpenseType.TAX ) from $expenseDetails ) )
then
System.out.println("################ It works ##################");
insertLogical("Bypass Process");
end
This is just more verbose than the forall, but it is exactly the same. Once the parser is fixed, you will be able to simply write:
rule "Do Not Process TAX" when
$report: ExpenseReport($expenseDetails: expenseDetails)
forall ( ExpenseDetails( expenseType == ExpenseType.TAX ) from $expenseDetails )
then
System.out.println("################ It works ##################");
insertLogical("Bypass Process");
end
BTW, may I ask you please to open a JIRA so we don't forget to fix this for 5.0?
Thanks, Edson
-- Edson Tirelli JBoss Drools Core Development Office: +55 11 3529-6000 Mobile: +55 11 9287-5646 JBoss, a division of Red Hat www.jboss.com
|
| Re: How check if all the values in a
collection match a criteria |
  Ireland |
2008-05-19 03:50:20 |
Hi,
thanks for your help, I created the JIRA as requested
(http:/
/jira.jboss.org/jira/browse/JBRULES-1611).
The workaround you suggest works only partially, if any of
the
ExpenseDetails is of type ExpenseType.TAX it will fire the
rule.
What I would like to do is to fire the rule only if all
ExpenseDetails
in the same report are of type ExpenseType.TAX.
Any help is more than welcome.
Thanks
Alessandro
Edson Tirelli wrote:
>
> Hmm, now that you mentioned, I see that our parser
is limiting the
> forall() CE, not allowing nested "from" CEs.
This is something we should
> fix, since the limitation is purely a parser
limitation.
>
> Anyway, for your case, the workaround is simply to
use the "raw"
> forall-equivalence: not( A() and not( B() ) ). So try
this:
>
> rule "Do Not Process TAX"
when
> $report: ExpenseReport($expenseDetails:
expenseDetails)
> not ( $ed : ExpenseDetails() from
$expenseDetails and
> not ( ExpenseDetails( this == $ed,
expenseType ==
> ExpenseType.TAX ) from $expenseDetails )
> )
> then
>
System.out.println("################ It works
> ##################");
> insertLogical("Bypass
Process");
> end
>
> This is just more verbose than the forall, but it is
exactly the
> same. Once the parser is fixed, you will be able to
simply write:
>
> rule "Do Not Process TAX"
when
> $report: ExpenseReport($expenseDetails:
expenseDetails)
> forall ( ExpenseDetails( expenseType ==
ExpenseType.TAX )
> from $expenseDetails )
> then
>
System.out.println("################ It works
> ##################");
> insertLogical("Bypass
Process");
> end
>
> BTW, may I ask you please to open a JIRA so we
don't forget to fix
> this for 5.0?
>
> Thanks,
> Edson
>
>
>
> 2008/5/18 Alessandro Di Bella <aldibella gmail.com
> <mailto:aldibella gmail.com>>:
>
> Hi,
>
> I have these two classes:
>
> ExpenseReport{
> Collection<ExpenseDetails> expenseDetails
> }
> ExpenseDetails{ ExpenseReport document
> ExpenseType expenseType
> }
>
> I am trying to create a rule that fires when all
the ExpenseDetails in a
> ExpenseReport are of the same type:
>
> rule "Do Not Process TAX"
when
> $report:
ExpenseReport($expenseDetails: expenseDetails)
> forall (
>
ExpenseDetails(document==$report, expenseType
> == ExpenseType.TAX)
> ) then
>
System.out.println("################ It works
> ##################");
> insertLogical("Bypass
Process");
> end
>
> For some reasons, it fires regardless that value
of
> ExpenseDetails.expenseType.
>
> I just started with drools and any help i more than
welcome.
>
> Thanks
>
> _______________________________________________
> rules-users mailing list
> rules-users lists.jboss.org <mailto:rules-users lists.jboss.org>
>
https://lists.jboss.org/mailman/listinfo/rules-users
>
>
>
>
> --
> Edson Tirelli
> JBoss Drools Core Development
> Office: +55 11 3529-6000
> Mobile: +55 11 9287-5646
> JBoss, a division of Red Hat www.jboss.com <http://www.jboss.com>
>
>
>
------------------------------------------------------------
------------
>
> _______________________________________________
> rules-users mailing list
> rules-users lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/rules-users
_______________________________________________
rules-users mailing list
rules-users lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users
|
|
| Re: Re: How check if all the values in
a collection match a criteria |

|
2008-05-19 08:32:51 |
|
Alessandro,
I'm not sure what the problem in your case is, but the syntax I showed you is the correct syntax for forall, since a forall is nothing more than not( A() and not( B() ... ) ). I created a JUnit 3 test case (since people was asking for junit examples) to reproduce the scenario and it works just fine:
================ public void testExpenses() throws Exception { Reader source = new InputStreamReader( getClass().getResourceAsStream( "/expenses.drl" ) ); PackageBuilder builder = new PackageBuilder();
builder.addPackageFromDrl( source ); RuleBase ruleBase = RuleBaseFactory.newRuleBase(); ruleBase.addPackage( builder.getPackage() ); StatefulSession session = ruleBase.newStatefulSession();
ArrayList<ExpenseReport> results = new ArrayList<ExpenseReport>(); session.setGlobal( "results", results ); // CASE 1: empty expense report, should fire ExpenseReport report1 = new ExpenseReport(new ArrayList<ExpenseDetail>());
session.insert( report1 ); session.fireAllRules(); assertEquals( 1, results.size() ); assertEquals( report1, results.get( 0 )); // CASE 2: non-empty expense report, with mixed details, should NOT fire
ExpenseDetail[] details2 = new ExpenseDetail[] { new ExpenseDetail(ExpenseType.TAX), new ExpenseDetail( ExpenseType.MEAL ) }; ExpenseReport report2 = new ExpenseReport(Arrays.asList( details2 )); session.insert( report2 );
session.fireAllRules(); assertEquals( 1, results.size() ); // CASE 3: non-empty expense report, with TAX-only details, should fire ExpenseDetail[] details3 = new ExpenseDetail[] { new ExpenseDetail(ExpenseType.TAX), new ExpenseDetail( ExpenseType.TAX ) };
ExpenseReport report3 = new ExpenseReport(Arrays.asList( details3 )); session.insert( report3 ); session.fireAllRules(); assertEquals( 2, results.size() ); assertEquals( report3, results.get( 1 ));
}
========== package com.sample
global java.util.List results;
rule "Check all expenses" when $report: ExpenseReport($expenseDetails: expenseDetails) not ( $ed : ExpenseDetail() from $expenseDetails and
not ( ExpenseDetail( this == $ed, type == ExpenseType.TAX ) from $expenseDetails ) ) then results.add( $report ); end ===========
If you can make this test break showing your problem, I may be able to help you out. | |