Limitations

While Jinaga uses LINQ to express specifications, not all LINQ syntax is supported.

Conditions Based On Fields

LINQ allows you to use comparison operators on fields of objects within a where clause. You can compare strings, integers, and other types using equality, inequality, and other operators.

However, Jinaga does not support this feature. Jinaga specifications are based only on the relationships between facts.

In one specific scenario, you can apply a pattern in order to filter based on the value of a field. If you can isolate the field in question, and if you want to search for an exact value, then you can use that fact as a query parameter.

For example, suppose you want to search for course offerings in a particular term. Making the name of the term a field of the offering will not work.

[FactType("Offering")]
public record Offering(string termName, Course course);

// This is an invalid specification.
// The parameters to Given must be facts, not values.
var offeringsInTerm = Given<School, string>.Match((school, termName, facts) =>
    from offering in facts.OfType<Offering>()
    where offering.course.school == school &&
        offering.termName == termName   // This is not supported by Jinaga
    select offering);

// Query for facts matching the specification.
var termName = "Fall 2024";
var offerings = await jinagaClient.Query(offeringsInTerm, school, termName);
// This is invalid because the parameters to Query must be facts, not values.

Instead, define a fact type that represents the term. Then, you can filter based on the relationship between the offering and the term.

[FactType("Term")]
public record Term(School school, string name);

[FactType("Offering")]
public record Offering(Term term, Course course);

// This is a valid specification.
var offeringsInTerm = Given<Term>.Match((term, facts) =>
    from offering in facts.OfType<Offering>()
    where offering.term == term
    select offering);

// First recreate the term fact to use as a query parameter.
var term = new Term(school, "Fall 2024");
// Then query for facts matching the specification.
var offerings = await jinagaClient.Query(offeringsInTerm, term);

FirstOrDefault

LINQ supports a family of methods that get an element from a collection. These methods include First, FirstOrDefault, Single, and SingleOrDefault.

Jinaga does not support these methods. The results of a Jinaga specification are always collections. If you need to get an element of a collection, first realize the collection to memory and then use one of the element methods.

Group By

LINQ supports a group by clause that allows you to group results by a particular field. This is useful for aggregating data and creating reports.

Jinaga does not support the group by clause. It only allows you to walk the graph, not to aggregate over it.

Join

LINQ supports a join clause that allows you to combine two sets of data based on a common field. This is useful for combining data from different sources.

Jinaga does not support the join clause. The only source that it supports is the fact repository facts. To join two sets of facts, use an additional from clause with facts.OfType<T>(). Add a where clause to specify the relationship between the two sets of facts.

Order By

LINQ supports an order by clause that allows you to sort results based on a field. You can sort in ascending or descending order.

Jinaga does not support the order by clause. The order of facts in the result set is not guaranteed. Specifications are best thought of as a set of facts that meet the criteria, not as a sequence of facts.

Overcoming Limitations

While Jinaga does not support these features, you can overcome these limitations by realizing results to memory. This happens when you call jinagaClient.Query, or when you receive a callback from jinagaClient.Watch. Once you have the results in memory, you can use LINQ to Objects to perform these operations.

Continue With

Building Applications

Jinaga is a product of Jinaga LLC.

Michael L Perry, President