While Jinaga uses LINQ to express specifications, not all LINQ syntax is supported.
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);
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.
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.
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.
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.
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.