New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support nested patterns and joins within ForAllElement #193
Comments
I think due to the implementation of VisitForAll which assumes the patterns are all of the same declaration type as "base", the "work around" will actually just cause downstream issues. Exists/Not seems to work for end-to-end cases however. I guess the "bug" here is that there's no validation for that at rule compile time. But i'm still not sure how to work around this or how ForAll can be changed to support this setup like Exists/Not can. |
I believe there is indeed a problem here. A rule element (in the RuleModel) can import declarations from the outer scope and can export declarations to the outer scope. It cannot however just expose declarations to the nested elements w/o also exporting them outside. |
@a046 while the above statement about declaration scopes is true, the situation with ForAll element is much deeper. ForAll element states that for all facts that match the base pattern, all of the subsequent patterns must also match. So, the first embedded assumption in its implementation is that all of these patterns are matching the same type of fact, so your example will not work even if scoping issue was somehow resolved. This also pretty much obviates the need to binding the patterns to declarations, since they are of no use, as you cannot join other facts in. |
Thanks for looking into this! That all does make sense from an implementation point of view. With how my facts are modeled, I need to be able to have conditions against joined facts for my Exists/ForAll pattern. I can't think of a nice/efficient work around for doing this if ForAll won't work. As an example, imagine the Customer and Order facts in the RuleBuilder sample was extended to also have an Item fact. A reasonable (albeit contrived) rule setup might be to find customers where all items (an attribute of Order) are InStock so the Orders can be dispatched. I doubt it worked before 0.9 from what I have seen in RuleTransformation.cs, I don't think multiple patterns are exposed to the Fluent API anyway? |
I'm not trying to imply it's not a useful feature, just trying to understand if it's a bug/regression or a new feature. This sounds like a new feature. When()
.Match<Customer>(() => customer)
.Match<Order>(() => order, x => x.Customer == customer, x => x.Items.All(i => i.InStock)); If When()
.Match<Customer>(() => customer)
.Match<Order>(() => order, x => x.Customer == customer)
.Query(() =>itemsInStock, q => q
.Match<Item>(x => x.Order == order)
.Collect()
.Where(x => x.All(i => i.InStock))
); Would that work? |
I agree, it seems like it's a feature as it's different to what the ForAllPattern currently does and as far as I'm aware there has been no regression in this behavior. I think the second solution using a collection might work, but I don't just have the equivalent of Order -> Item. I have some other facts being joined on to my equivalent of Order which would also require conditions too, so i'm not too sure if I can do that and still only return Customers where all Orders (+ joined objects) match some set of conditions? I think it should also work by adding multiple queries assuming it works with one, but i'm not sure how the second example above actually works to be honest? I'll have to test it, because i'm not as familiar with the "Query" fluent syntax, but at first glance it looks it would match on Customers where at least one Order is in stock rather than Customers where all Items on all Orders are in stock? On further thought, I also need to make sure some conditions on all Orders for the customer are met too - so I don't think the solution above can work as adding the conditions to the Match for Order would pre-filter the orders, and adding them in a query will cause the same scoping problem discussed earlier. |
A possible workaround that I dismissed early on was to make two collection patterns of Orders joined to Customers. One set has conditions + joins applied, the other nothing but the Customer -> Order join. I could then check that the count of the two collections were equal. Without knowing what the resulting internal representations would look like, i'm concerned about the memory usage/performance of that however, but it might work? |
Hey Sergiy, I hope you are doing well! I noticed there was some refactoring work around this area a little while ago, any thoughts on how complicated this feature would be to implement? Is it on your roadmap, or something you'd like help with? |
Hello, everything is great, thank you! Hope it's all good on your side too. |
Thanks, I'm good too! Those performance improvements sound pretty good, definitely understand that being the priority. I'll have to look a bit more into how the quantifiers work internally and everything works then and maybe also revisit the workarounds. |
I’m trying to create a ”ForAll” rule using the RuleBuilder API where additional facts are joined onto the fact type used in the ForAll rule.
This can be achieved with Any/None rules by using the GroupBuilder, but the patterns collection on ForAll does not work in the same way. See below:
From investigation, it appears that the ForAll patterns cannot “import” parameters from each other and require their dependent patterns to be added to the left hand side of the rule rather than just the ForAllBuilder.
I’m not sure if this is a bug, feature request or support issue. Am I using the ForAllPattern incorrectly and is there any reason Any/None take a group but ForAll cant?
The text was updated successfully, but these errors were encountered: