Class StructureQueryBuilder.OpStep<B extends StructureQueryBuilder<B>>

Object
OpStep<B>
Enclosing class:
StructureQueryBuilder<B extends StructureQueryBuilder<B>>

public static class StructureQueryBuilder.OpStep<B extends StructureQueryBuilder<B>> extends Object

This class lets you add operator to the relational constraint being built, or to combine the already added relation with another one via or().

operator specifies how basicConstraint is applied to relation:

  1. in, is, and equals specify that a row is matched if its relatives match the basic constraint.

    For example, consider child.in.issueKeys("TS-129", "TS-239"). The relation is child, so the relatives in question are sub-rows. So, a row matches this query if at least one sub-row is TS-129 or TS-239.

    There is no difference between these three operators; different forms exist for the purpose of a more natural way to express different species of constraints.

  2. notIn, isNot, and notEquals are negated versions of in, is, equals. They specify that a row is matched if none of its relatives match the basic constraint. Importantly, rows with no relatives are matched.

    For example, consider child.notIn.issueKeys("TS-129", "TS-239"). A row is matched if no sub-row of it is TS-129 or TS-239; thus, this constraint matches all rows that either have no sub-rows or do not have these two issues among their sub-rows.

    Using a relational constraint with one of these operators is equivalent to using a negation of relational constraint with the corresponding non-negated operator. E.g., the constraint above is equivalent to not().child.in.issueKeys("TS-129", "TS-239").

    But, using these operators is very not the same as negating basicConstraint: first, having relatives other than X is not the same as not having relatives X, second, rows with no children are not matched. E.g., child.in.not().issueKeys("TS-129", "TS-239") matches all rows with sub-rows, such that at least one of their sub-rows is not TS-129 nor TS-239. In other words, it matches all rows with sub-rows except those having only TS-129 or TS-239 as sub-rows.

  3. of matches relatives of rows matching the basic constraint. Thus, the relational constraint behaves as if we first find all rows that satisfy basicConstraint, then select their relatives.

    For example, consider child.of.issueKeys("TS-129", "TS-239"): a row matches if it is a child of either TS-129 or TS-239.

To illustrate the difference between of and in (is, equals), let's compare queries q4 and q5 from the class documentation using this forest:

   project TS
     version 1.2     q4
       TS-129      *
         TS-48          q5
       TS-239      *
         TS-49          q5
       TS-50
     version 1.3     q4
       TS-239      *
         TS-49          q5

   q4: child.in.issueKeys("TS-129", "TS-239")
   q5: child.of.issueKeys("TS-129", "TS-239")
 
Asterisks mark rows matching the basic constraint, and q4/q5 mark rows matching the corresponding queries.

One may note that for any relation, there is a corresponding "inverse" relation: for example, child-parent. A relational constraint using operator in (is, equals) is equivalent to a relational constraint using an inverse relation with operator of. That is,
child.in.issueKeys("TS-129", "TS-239")
is the same as
parent.of.issueKeys("TS-129", "TS-239").
Compare also examples q6 and q7 from the class documentation.