I need to model an approval process. Before it was pretty simple. Two roles had to approve something, and then we could go on to the next step:
public class Approved
{
public string ApproverRole;
}
var approvals = Subscribe<Approved>();
var vpOfFinance = approvals.Where(e => e.ApproverRole == "Finance VP");
var vpOfSales = approvals.Where(e => e.ApproverRole == "Sales VP");
var approvedByAll = vpOfFinance.Zip(vpOfSales, Tuple.Create);
approvedByAll.Subscribe(_ => SomeInterestingBusinessProcess());
But now there is a new requirement: the number of roles required to approve something can vary:
public class ApprovalRequested
{
public string[] Roles;
}
var approvalRequest = Subscribe<ApprovalRequested>().Take(1);
var approvals = Subscribe<Approved>();
var approvedByAll = ???;
approvedByAll.Subscribe(_ => SomeInterestingBusinessProcess());
I feel like I am missing something pretty obvious here… can anyone point me in the right direction?
Edit
To clarify: The approval process is on a per item basis. The order that the approvals can arrive in is undefined. We don’t care if one role approves an item multiple times.
The problem can essentially be reduced to creating a
Setfrom a stream of values where values may be out of order or many in nature.If N is the cardinality of the set, we can trivially assume that the process will not proceed until at least N types of values (roles in this case) have been pushed.
Here’s a sample solution of the Zip operator; perhaps this can get you started:
Test:
One issue here is that you may lose out on the initial values while the groups are being formed, so you might want to incorporate that by rewriting the method as
IObservable<IList<T>> Zip<TKey, T>(this IGroupedObservable<TKey, T> observables).