Projections

To populate a user interface, a specification will need to add details to its results. To accomplish this, create an object in the select clause. The object can include properties that are computed from child specifications.

For the blog application, we'll want to display a list of sites. The user will need to see the name of each site in the list. Let's modify the sitesByUser specification to include the names of each site.

var sitesByUser = Given<User>.Match((user, facts) =>
    from site in facts.OfType<Site>()
    where site.creator == user
    where !facts.Any<SiteDeleted>(
        sd => sd.site == site &&
        !facts.Any<SiteRestored>(sr => sr.deleted == sd))
    // Select an anonymous object with information about the site
    select new
    {
        // Include the site fact
        Site = site,
        // Get the list of names for the site
        Names =
            from name in facts.OfType<SiteName>()
            where name.site == site
            where !facts.Any<SiteName>(next => next.prior.Contains(name))
            // Pick the value, not the fact
            select name.value
    });

var sites = await jinagaClient.Query(sitesByUser, user);

sites

With this structure, the user interface can generate a list of sites. The Names property is going to be a collection of names, not a single value. The user interface might use FirstOrDefault to turn it into a single value.

var sitesViewModel = sites.Select(s => new
{
    Name = s.Names.FirstOrDefault() ?? "New site"
});

sitesViewModel

Continue With

Additional Mutable Properties

Jinaga is a product of Jinaga LLC.

Michael L Perry, President