Syntax Alternatives

In most Jinaga.NET documentation, I use the LINQ query expression syntax. This features keywords like from, where, and select. Some developers prefer the LINQ method syntax. This syntax uses methods like Where, Select, and SelectMany with lambda expressions. Jinaga specifications work equally well in either format.

SelectMany

We've seen several examples of specifications that chain from clauses together. This is equivalent to using the SelectMany method in the method syntax. Let's look at an example.

This was the specification that we used to find all the carts in an environment for a user before simplifying it with Relation properties.

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 &&
        customer.environment == environment
    from cart in facts.OfType<Cart>()
    where cart.customer == customer
    select cart);

This can be rewritten using SelectMany like this:

var cartsInEnvironmentForUser = Given<Environment, User>.Match((environment, user, facts) =>
    facts.OfType<CustomerBuyer>()
        .Where(customerBuyer => customerBuyer.buyer == user)
        .SelectMany(customerBuyer =>
            facts.OfType<Customer>()
                .Where(customer => customerBuyer.customer == customer &&
                    customer.environment == environment)
                .SelectMany(customer =>
                    facts.OfType<Cart>()
                        .Where(cart => cart.customer == customer)
                )
        )
);

I find the query expression syntax easier to read. But the method syntax is more flexible. The choice is yours.

Predicate in OfType

Facts always have to be related to prior facts. This could be done by following the facts.OfType<T>() method with a call to Where. But since this is so common, facts.OfType<T> can take a predicate directly.

var albumsByUser = Given<User>.Match((user, facts) =>
    facts.OfType<Album>(album => album.creator == user));

Combining this with the SelectMany method, we can simplify the specification above.

var cartsInEnvironmentForUser = Given<Environment, User>.Match((environment, user, facts) =>
    facts.OfType<CustomerBuyer>(customerBuyer => customerBuyer.buyer == user)
        .SelectMany(customerBuyer =>
            facts.OfType<Customer>(customer => customerBuyer.customer == customer &&
                customer.environment == environment)
                .SelectMany(customer =>
                    facts.OfType<Cart>(cart => cart.customer == customer)
                )
        )
);

Any

Jinaga provides the facts.Any<T> method to check for the existence of a fact. This is equivalent to the LINQ Any method when applied to facts.OfType<T>.

Previously we looked at a specification that excluded albums that have been deleted.

var albumsByUser = Given<User>.Match((user, facts) =>
    facts.OfType<Album>()
        .Where(album => album.creator == user &&
            !facts.Any<AlbumDelete>(delete => delete.album == album))
);

This can also be written using the Any method like this:

var albumsByUser = Given<User>.Match((user, facts) =>
    facts.OfType<Album>()
        .Where(album => album.creator == user &&
            !facts.OfType<AlbumDelete>().Any(delete => delete.album == album))
);

Or you can apply the Where clause before the Any method.

var albumsByUser = Given<User>.Match((user, facts) =>
    facts.OfType<Album>()
        .Where(album => album.creator == user &&
            !facts.OfType<AlbumDelete>()
                .Where(delete => delete.album == album)
                .Any())
);

The facts.Any<T> method is provided to simplify these expressions.

Continue With

Limitations

Jinaga is a product of Jinaga LLC.

Michael L Perry, President