Once you have a minimal path to the results you want, you can select a projection from that point.
Create an anonymous object after select
containing all of the information you need.
This can include nested specifications.
Continuing from the cart example, let's look at the details that we want to include. First, let's get the name of the customer. The model looks like this:
Within our projection, we'll add a property to get the customer names.
var cartsInEnvironmentForUser = 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
select new
{
Cart = cart,
CustomerNames =
from customerName in facts.OfType<CustomerName>()
where customerName.customer == customer
where !facts.Any<CustomerName>(next => next.prior.Contains(customerName))
select customerName.value
});
The nested specification uses !facts.Any<T>
to filter out customer names that have been superseded.
This ensures that we only see the current customer names.
We will talk about conditions in a bit more detail later.
The nested specification also selects a field of the customerName
fact.
We want to display the name, so we will need its value.
Fields can appear in projections.
If you want to select another fact, however, you will instead need to label it and include it in the path.
Let's continue. We also want the cart items. Add this to the projection.
var cartsInEnvironmentForUser = 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
select new
{
Cart = cart,
CustomerNames =
from customerName in facts.OfType<CustomerName>()
where customerName.customer == customer
where !facts.Any<CustomerName>(next => next.prior.Contains(customerName))
select customerName.value,
Items =
from cartItem in facts.OfType<CartItem>()
where cartItem.cart == cart
select cartItem
});
It's not just the item that we want. We also want to display the product name and quantity. Here's the part of the model that deals with those properties:
From this graph, we can draw another pair of paths.
One path leads us from Cart.Item
through Product
to Product.Name
.
The other path leads us from Cart.Item
directly to Cart.Item.Quantity
.
Add these two paths to the nested projection.
var cartsInEnvironmentForUser = 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
select new
{
Cart = cart,
CustomerNames =
from customerName in facts.OfType<CustomerName>()
where customerName.customer == customer
where !facts.Any<CustomerName>(next => next.prior.Contains(customerName))
select customerName.value,
Items =
from cartItem in facts.OfType<CartItem>()
where cartItem.cart == cart
select new
{
CartItem = cartItem,
ProductNames =
from productName in facts.OfType<ProductName>()
where productName.product == cartItem.product
where !facts.Any<ProductName>(next => next.prior.Contains(productName))
select productName.value,
Quantities =
from quantity in facts.OfType<CartItemQuantity>()
where quantity.item == cartItem
select quantity
}
});
These nested projections give us all the information we need about the cart and its items. Carefully construct each path within the projections to select exactly the results you want.