Most patterns will call for the specification to exclude facts that meet certain criteria. These criteria are expressed in terms of the existence of successors.
Use !facts.Any<T>
to write a condition based on existence.
Pass in a predicate to trace a path to facts of type T
.
This will exclude the fact if any matching successor exists.
For example, the user might want to delete an album. This would be supported with the following model:
You can write a specification that excludes albums that have been deleted.
Use a where
clause to only include albums that do not have an AlbumDelete
fact.
var albumsByUser = Given<User>.Match((user, facts) =>
from album in facts.OfType<Album>()
where album.creator == user &&
!facts.Any<AlbumDelete>(delete => delete.album == album)
select album);
Go one level deeper to implement the restore pattern.
Add an AlbumRestore
fact to the model.
Then modify the specification to exclude albums that have been deleted but not restored.
var albumsByUser = Given<User>.Match((user, facts) =>
from album in facts.OfType<Album>()
where album.creator == user &&
!facts.Any<AlbumDelete>(delete => delete.album == album &&
!facts.Any<AlbumRestore>(restore => restore.delete == delete))
select album);
You can also go in the opposite direction. You can include only those facts that have a certain successor. For example, on the checkout screen, you might want to list only the carts that contain at least one item.
var cartsToCheckOut = Given<Environment, User>.Match((environment, user, facts) =>
from customerBuyer in facts.OfType<CustomerBuyer>()
where customerBuyer.buyer == user
from customer in facts.OfType<Customer>()
where customerBuyer.customer == customer
where customer.environment == environment
from cart in facts.OfType<Cart>()
where cart.customer == customer &&
facts.Any<CartItem>(cartItem => cartItem.cart == cart)
select cart);