Optionals
Optional patterns can be used in match stages to optionally match a pattern,
or in insert stages to insert a pattern if all the variables involved are bound.
Schema for the following examples
#!test[schema, commit]
define
attribute email, value string;
attribute phone, value string;
attribute username, value string;
relation friendship, relates friend @card(0..2);
relation marriage, relates spouse @card(0..2);
relation policy, relates covered @card(0..);
entity user,
owns username, owns email, owns phone,
plays friendship:friend;
entity person, plays marriage:spouse, plays policy:covered;
Syntax & Basic behavior
try { <pattern> };
match
Variables which are present only in the try block are considered optional.
If the entire optional pattern matches the data, it returns an answer per match.
If it has no matches, it produces a single answer with all optional variables bound to None.
#!test[read]
match
$person isa person;
try {
$_ isa marriage, links (spouse: $person, spouse: $spouse);
};
Here, $spouse is bound to the spouse if $person is in a marriage.
Else, $spouse is bound to None
insert, update, & delete
Optional patterns in insert, update, or delete stages execute only if ALL the variables present in them are bound.
match
$person isa person;
try {
$_ isa marriage, links (spouse: $person, spouse: $spouse);
};
insert
$policy isa policy;
$policy links (covered: $person);
try { $policy links (covered: $spouse); };
If $person is in a marriage, the match stage binds $spouse and the insert stage adds them to the policy.
put
Because a put stage only inserts data if no existing data matches the body of the put, the patterns in a try block of a put stage only attempt to insert data if the mandatory patterns (i.e. those
outside try blocks) fail to produce a match. When inserting data, put behaves identically to an insert stage in that a try block only executes if all referenced variables are bound.
#!test[write, rollback]
match
$person isa person;
$spouse isa person;
try {
$policy isa policy, links (covered: $person);
};
put
$_ isa marriage, links (spouse: $person, spouse: $spouse);
try {
$policy links (covered: $spouse);
};
In this example, if the marriage relation already exists, the put stage does not attempt to add $spouse to the optionally bound $policy.
If this behavior is not desirable, the try block should be put in a separate insert stage instead.
#!test[write, rollback]
match
$person isa person;
$spouse isa person;
try {
$policy isa policy, links (covered: $person);
not { $policy links (covered: $spouse); };
};
put
$_ isa marriage, links (spouse: $person, spouse: $spouse);
insert
try {
$policy links (covered: $spouse);
};
In this pipeline, the marriage relation is created if it does not already exist, and $spouse is always inserted as a roleplayer in $policy provided it is bound.
|
In particular, a put stage with only
In this example the |
Behavior in match clauses
Single origin
In the stage that it first occurs, An optional variable may only occur in a single try-block.
#!test[read, fail_at=runtime]
match
$person isa person;
try {
$_ isa marriage, links (spouse: $person, spouse: $spouse);
};
try {
$policy isa policy, links (covered: $spouse); # Invalid
};
Optional variables in subsequent stages
An optional variable can be used in subsequent stages. An unbound optional variable causes the pattern to fail.
The following is a valid way to express the intent of the example above:
#!test[read]
match
$person isa person;
try {
$_ isa marriage, links (spouse: $person, spouse: $spouse);
};
match
try {
$policy isa policy, links (covered: $spouse);
};