-
Language:
English
-
Language:
English
Red Hat Training
A Red Hat training course is available for Red Hat JBoss Data Virtualization
6.5. Query Object Model Extensions
The extensions in the JCR-SQL and JCR-SQL2 languages can also be used when building queries programmatically using the JCR Query Object Model API. The hierarchical database defines the
org.modeshape.jcr.api.query.qom.QueryObjectModelFactory
interface that extends the standard javax.jcr.query.qom.QueryObjectModelFactory
interface, and which contains methods providing ways to construct a QOM with the extended features.
6.5.1. Join Types
The standard
javax.jcr.query.qom.QueryObjectModelFactory
interface uses a String
to specify the join type:
package javax.jcr.query.qom; public interface QueryObjectModelFactory { ... /** * Performs a join between two node-tuple sources. * * The query is invalid if 'left' is the same source as 'right'. * * @param left the left node-tuple source; non-null * @param right the right node-tuple source; non-null * @param joinType either QueryObjectModelConstants.JCR_JOIN_TYPE_INNER, * QueryObjectModelConstants.JCR_JOIN_TYPE_LEFT_OUTER, or * QueryObjectModelConstants.JCR_JOIN_TYPE_RIGHT_OUTER. * @param joinCondition the join condition; non-null * @return the join; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, * on {@link #createQuery}), and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public Join join( Source left, Source right, String joinType, JoinCondition joinCondition ) throws InvalidQueryException, RepositoryException; ... }
In addition to the three standard constants, the hierarchical database supports two additional constant values:
javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_INNER
javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_LEFT_OUTER
javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_RIGHT_OUTER
org.modeshape.jcr.api.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_CROSS
org.modeshape.jcr.api.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_FULL_OUTER
6.5.2. Set Operations
Creating a set query is very similar to creating a normal
SELECT
type query, but instead the following on org.modeshape.jcr.api.query.qom.QueryObjectModelFactory
are used:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Creates a query with one or more selectors. * * @param source the node-tuple source; non-null * @param constraint the constraint, or null if none * @param orderings zero or more orderings; null is equivalent to a zero-length array * @param columns the columns; null is equivalent to a zero-length array * @param limit the limit; null is equivalent to having no limit * @param isDistinct true if the query should return distinct values; or false if no * duplicate removal should be performed * @return the select query; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test and the parameters given fail that * test. See the individual QOM factory methods for the validity criteria * of each query element. * @throws RepositoryException if another error occurs. */ public SelectQuery select( Source source, Constraint constraint, Ordering[] orderings, Column[] columns, Limit limit, boolean isDistinct ) throws InvalidQueryException, RepositoryException; /** * Creates a query command that effectively appends the results of the right-hand query * to those of the left-hand query. * * @param left the query command that represents left-side of the set operation; * non-null and must have columns that are equivalent and union-able to those * of the right-side query * @param right the query command that represents right-side of the set operation; * non-null and must have columns that are equivalent and union-able to those * of the left-side query * @param orderings zero or more orderings; null is equivalent to a zero-length array * @param limit the limit; null is equivalent to having no limit * @param all true if duplicate rows in the left- and right-hand side results should * be included, or false if duplicate rows should be eliminated * @return the select query; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test and the parameters given fail * that test. See the individual QOM factory methods for the validity criteria * of each query element. * @throws RepositoryException if another error occurs. */ public SetQuery union( QueryCommand left, QueryCommand right, Ordering[] orderings, Limit limit, boolean all ) throws InvalidQueryException, RepositoryException; /** * Creates a query command that returns all rows that are both in the result of the * left-hand query and in the result of the right-hand query. * * @param left the query command that represents left-side of the set operation; * non-null and must have columns that are equivalent and union-able to those * of the right-side query * @param right the query command that represents right-side of the set operation; * non-null and must have columns that are equivalent and union-able to those * of the left-side query * @param orderings zero or more orderings; null is equivalent to a zero-length array * @param limit the limit; null is equivalent to having no limit * @param all true if duplicate rows in the left- and right-hand side results should * be included, or false if duplicate rows should be eliminated * @return the select query; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test and the parameters given fail * that test. See the individual QOM factory methods for the validity criteria * of each query element. * @throws RepositoryException if another error occurs. */ public SetQuery intersect( QueryCommand left, QueryCommand right, Ordering[] orderings, Limit limit, boolean all ) throws InvalidQueryException, RepositoryException; /** * Creates a query command that returns all rows that are in the result of the left-hand * query but not in the result of the right-hand query. * * @param left the query command that represents left-side of the set operation; * non-null and must have columns that are equivalent and union-able to those * of the right-side query * @param right the query command that represents right-side of the set operation; * non-null and must have columns that are equivalent and union-able to those * of the left-side query * @param orderings zero or more orderings; null is equivalent to a zero-length array * @param limit the limit; null is equivalent to having no limit * @param all true if duplicate rows in the left- and right-hand side results should * be included, or false if duplicate rows should be eliminated * @return the select query; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test and the parameters given fail * that test. See the individual QOM factory methods for the validity criteria * of each query element. * @throws RepositoryException if another error occurs. */ public SetQuery except( QueryCommand left, QueryCommand right, Ordering[] orderings, Limit limit, boolean all ) throws InvalidQueryException, RepositoryException; ... }
Note that the
select(...)
method returns a SelectQuery
while the union(...)
, intersect(...)
and except(...)
methods return a SetQuery
. The SelectQuery
and SetQuery
interfaces are defined by the hierarchical database and both extend the QueryCommand
interface. This interface is then used in the methods to create SetQuery
.
The
SetQuery
object is not executable. To create the corresponding javax.jcr.Query
object, pass the SetQuery
to the following method on org.modeshape.jcr.api.query.qom.QueryObjectModelFactory
:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Creates a set query. * * @param command set query; non-null * @return the executable query; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test and the parameters given fail * that test. See the individual QOM factory methods for the validity criteria * of each query element. * @throws RepositoryException if another error occurs. */ public SetQueryObjectModel createQuery( SetQuery command ) throws InvalidQueryException, RepositoryException; ... }
The resulting
SetQueryObjectModel
extends javax.jcr.query.Query
and SetQuery
and can be executed and treated similarly to the standard javax.jcr.query.qom.QueryObjectModel
(that also extends javax.jcr.query.Query
).
6.5.3. Correlated Subqueries
The hierarchical database defines a
Subquery
interface that extends the standard javax.jcr.query.qom.StaticOperand
interface, and thus can be used on the right-hand side of any Criteria
:
public interface Subquery extends StaticOperand { /** * Gets the {@link QueryCommand} that makes up the subquery. * * @return the query command; non-null */ public QueryCommand getQuery(); }
Subqueries can be created by passing a
QueryCommand
into this org.modeshape.jcr.query.qom.QueryObjectModelFactory
method:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Creates a subquery that can be used as a {@link StaticOperand} in another query. * * @param subqueryCommand the query command that is to be used as the subquery * @return the constraint; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, * on {@link #createQuery}), and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public Subquery subquery( QueryCommand subqueryCommand ) throws InvalidQueryException, RepositoryException; ... }
The resulting
Subquery
is a StaticOperand
that can then be used to create a Criteria
.
6.5.4. Removing Duplicate Rows
The
org.modeshape.jcr.query.qom.QueryObjectModelFactory
interface includes a variation of the standard QueryObjectModeFactory.select(...)
method with an additional isDistinct
flag that controls whether duplicate rows should be removed:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Creates a query with one or more selectors. * * @param source the node-tuple source; non-null * @param constraint the constraint, or null if none * @param orderings zero or more orderings; null is equivalent to a zero-length array * @param columns the columns; null is equivalent to a zero-length array * @param limit the limit; null is equivalent to having no limit * @param isDistinct true if the query should return distinct values; or false if no * duplicate removal should be performed * @return the select query; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test and the parameters given fail * that test. See the individual QOM factory methods for the validity criteria * of each query element. * @throws RepositoryException if another error occurs. */ public SelectQuery select( Source source, Constraint constraint, Ordering[] orderings, Column[] columns, Limit limit, boolean isDistinct ) throws InvalidQueryException, RepositoryException; ... }
6.5.5. Limit and Offset Results
The hierarchical database defines a
Limit
interface as a top-level object that can be used to create queries that limit the number of rows and/or skip a number of initial rows:
public interface Limit { /** * Get the number of rows skipped before the results begin. * * @return the offset; always 0 or a positive number */ public int getOffset(); /** * Get the maximum number of rows that are to be returned. * * @return the maximum number of rows; always positive, or equal to Integer.MAX_VALUE if there is no limit */ public int getRowLimit(); /** * Determine whether this limit clause is necessary. * * @return true if the number of rows is not limited and there is no offset, or false otherwise */ public boolean isUnlimited(); /** * Determine whether this limit clause defines an offset. * * @return true if there is an offset, or false if there is no offset */ public boolean isOffset(); }
These range constraints can be constructed using this
org.modeshape.jcr.query.qom.QueryObjectModelFactory
method:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Evaluates to a limit on the maximum number of tuples in the results and the * number of rows that are skipped before the first tuple in the results. * * @param rowLimit the maximum number of rows; must be a positive number, or Integer.MAX_VALUE if there is to be a * non-zero offset but no limit * @param offset the number of rows to skip before beginning the results; must be 0 or a positive number * @return the operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public Limit limit( int rowLimit, int offset ) throws InvalidQueryException, RepositoryException; ... }
The
Limit
objects can then be used when creating queries using a variation of the standard QueryObjectModeFactory.select(...)
defined in the org.modeshape.jcr.query.qom.QueryObjectModelFactory
interface:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Creates a query with one or more selectors. * * @param source the node-tuple source; non-null * @param constraint the constraint, or null if none * @param orderings zero or more orderings; null is equivalent to a zero-length array * @param columns the columns; null is equivalent to a zero-length array * @param limit the limit; null is equivalent to having no limit * @param isDistinct true if the query should return distinct values; or false if no * duplicate removal should be performed * @return the select query; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test and the parameters given fail * that test. See the individual QOM factory methods for the validity criteria * of each query element. * @throws RepositoryException if another error occurs. */ public SelectQuery select( Source source, Constraint constraint, Ordering[] orderings, Column[] columns, Limit limit, boolean isDistinct ) throws InvalidQueryException, RepositoryException; ... }
Similarly, the
Limit
objects can be passed to the hierarchical database except(...)
, union(...)
, intersect(...)
methods, too.
6.5.6. Depth Constraints
The hierarchical database defines a
DepthPath
interface that extends the standard javax.jcr.query.qom.DynamicOperand
interface, and thus can be used as part of a WHERE
clause to constrain the depth of the nodes accessed by a selector:
public interface NodeDepth extends javax.jcr.query.qom.DynamicOperand { /** * Get the selector symbol upon which this operand applies. * * @return the one selector names used by this operand; never null */ public String getSelectorName(); }
These range constraints can be constructed using this
org.modeshape.jcr.query.qom.QueryObjectModelFactory
method:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Evaluates to a LONG value equal to the depth of a node in the specified selector. * * The query is invalid if selector is not the name of a selector in the query. * * @param selectorName the selector name; non-null * @return the operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public NodeDepth nodeDepth( String selectorName ) throws InvalidQueryException, RepositoryException; ... }
6.5.7. Path Constraints
The hierarchical database defines a
NodePath
interface that extends the standard javax.jcr.query.qom.DynamicOperand
interface, and thus can be used as part of a WHERE
clause to constrain the path of nodes accessed by a selector:
public interface NodePath extends javax.jcr.query.qom.DynamicOperand { /** * Get the selector symbol upon which this operand applies. * * @return the one selector names used by this operand; never null */ public String getSelectorName(); }
These range constraints can be constructed using this
org.modeshape.jcr.query.qom.QueryObjectModelFactory
method:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Evaluates to a PATH value equal to the prefix-qualified path of a node in the specified selector. * * The query is invalid if selector is not the name of a selector in the query. * * @param selectorName the selector name; non-null * @return the operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public NodePath nodePath( String selectorName ) throws InvalidQueryException, RepositoryException; ... }
6.5.8. Criteria on References From a Node
The hierarchical database defines a
ReferenceValue
interface that extends the standard javax.jcr.query.qom.DynamicOperand
interface, and thus can be used as part of a WHERE
or ORDER BY
clause:
public interface ReferenceValue extends DynamicOperand { ... /** * Get the selector symbol upon which this operand applies. * * @return the one selector names used by this operand; never null */ public String getSelectorName(); /** * Get the name of the one reference property. * * @return the property name; or null if this operand applies to any reference property */ public String getPropertyName(); }
These reference value operand allow a query to easily place constraints on a particular REFERENCE property or (more importantly) any REFERENCE properties on the nodes. The former is a more simple alternative to using a regular comparison constraint with the REFERENCE property on one side and the
jcr:uuid
property on the other. The latter effectively means "where the node references (with any property) some other nodes", and this is something that standard JCR-SQL2 cannot represent.
They are created using these
org.modeshape.jcr.query.qom.QueryObjectModelFactory
methods:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Creates a dynamic operand that evaluates to the REFERENCE value of the any property * on the specified selector. * * The query is invalid if: * - selector is not the name of a selector in the query, or * - property is not a syntactically valid JCR name. * * @param selectorName the selector name; non-null * @return the operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public ReferenceValue referenceValue( String selectorName ) throws InvalidQueryException, RepositoryException; /** * Creates a dynamic operand that evaluates to the REFERENCE value of the specified * property on the specified selector. * * The query is invalid if: * - selector is not the name of a selector in the query, or * - property is not a syntactically valid JCR name. * * @param selectorName the selector name; non-null * @param propertyName the reference property name; non-null * @return the operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public ReferenceValue referenceValue( String selectorName, String propertyName ) throws InvalidQueryException, RepositoryException; ... }
6.5.9. Range Criteria
The hierarchical database defines a
Between
interface that extends the standard javax.jcr.query.qom.Constraint
interface, and thus can be used as part of a WHERE
clause:
public interface Between extends Constraint { /** * Get the dynamic operand specification. * * @return the dynamic operand; never null */ public DynamicOperand getOperand(); /** * Get the lower bound operand. * * @return the lower bound; never null */ public StaticOperand getLowerBound(); /** * Get the upper bound operand. * * @return the upper bound; never null */ public StaticOperand getUpperBound(); /** * Return whether the lower bound is to be included in the results. * * @return true if the {@link #getLowerBound() lower bound} is to be included, or false otherwise */ public boolean isLowerBoundIncluded(); /** * Return whether the upper bound is to be included in the results. * * @return true if the {@link #getUpperBound() upper bound} is to be included, or false otherwise */ public boolean isUpperBoundIncluded(); }
These range constraints can be constructed using this
org.modeshape.jcr.query.qom.QueryObjectModelFactory
method:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Tests that the value (or values) defined by the supplied dynamic operand are * within a specified range. The range is specified by a lower and upper bound, * and whether each of the boundary values is included in the range. * * @param operand the dynamic operand describing the values that are to be constrained * @param lowerBound the lower bound of the range * @param upperBound the upper bound of the range * @param includeLowerBound true if the lower boundary value is not be included * @param includeUpperBound true if the upper boundary value is not be included * @return the constraint; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public Between between( DynamicOperand operand, StaticOperand lowerBound, StaticOperand upperBound, boolean includeLowerBound, boolean includeUpperBound ) throws InvalidQueryException, RepositoryException; ... }
To create a
NOT BETWEEN ...
criteria, create the Between
criteria object, and then pass that into the standard QueryObjectModelFactory.not(Criteria)
method.
6.5.10. Set Criteria
The hierarchical database defines a
SetCriteria
interface that extends the standard javax.jcr.query.qom.Constraint
interface, and thus can be used as part of a WHERE
clause:
public interface SetCriteria extends Constraint { /** * Get the dynamic operand specification for the left-hand side of the set criteria. * * @return the dynamic operand; never null */ public DynamicOperand getOperand(); /** * Get the static operands for this set criteria. * * @return the static operand; never null and never empty */ public Collection<? extends StaticOperand> getValues(); }
These set constraints can be constructed using this
org.modeshape.jcr.query.qom.QueryObjectModelFactory
method:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Tests that the value (or values) defined by the supplied dynamic operand are * found within the specified set of values. * * @param operand the dynamic operand describing the values that are to be constrained * @param values the static operand values; may not be null or empty * @return the constraint; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public SetCriteria in( DynamicOperand operand, StaticOperand... values ) throws InvalidQueryException, RepositoryException; ... }
To create a
NOT IN
criteria, create the IN
criteria to get a SetCriteria
object, and then pass that into the standard QueryObjectModelFactory.not(Criteria)
method.
6.5.11. Arithmetic Operands
The hierarchical database defines an
ArithmeticOperand
interface that extends the javax.jcr.query.qom.DynamicOperand
, and thus can be used anywhere a DynamicOperand
can be used.
public interface ArithmeticOperand extends DynamicOperand { /** * Get the operator for this binary operand. * * @return the operator; never null */ public String getOperator(); /** * Get the left-hand operand. * * @return the left-hand operator; never null */ public DynamicOperand getLeft(); /** * Get the right-hand operand. * * @return the right-hand operator; never null */ public DynamicOperand getRight(); }
These can be constructed using additional
org.modeshape.jcr.query.qom.QueryObjectModelFactory
methods:
package org.modeshape.jcr.api.query.qom; public interface QueryObjectModelFactory { ... /** * Create an arithmetic dynamic operand that adds the numeric value of the two supplied operand(s). * * @param left the left-hand-side operand; not null * @param right the right-hand-side operand; not null * @return the dynamic operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public ArithmeticOperand add( DynamicOperand left, DynamicOperand right ) throws InvalidQueryException, RepositoryException; /** * Create an arithmetic dynamic operand that subtracts the numeric value of the second operand from the numeric value of the * first. * * @param left the left-hand-side operand; not null * @param right the right-hand-side operand; not null * @return the dynamic operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public ArithmeticOperand subtract( DynamicOperand left, DynamicOperand right ) throws InvalidQueryException, RepositoryException; /** * Create an arithmetic dynamic operand that multplies the numeric value of the first operand by the numeric value of the * second. * * @param left the left-hand-side operand; not null * @param right the right-hand-side operand; not null * @return the dynamic operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public ArithmeticOperand multiply( DynamicOperand left, DynamicOperand right ) throws InvalidQueryException, RepositoryException; /** * Create an arithmetic dynamic operand that divides the numeric value of the first operand by the numeric value of the * second. * * @param left the left-hand-side operand; not null * @param right the right-hand-side operand; not null * @return the dynamic operand; non-null * @throws InvalidQueryException if a particular validity test is possible on this method, * the implemention chooses to perform that test (and not leave it until later, on createQuery), * and the parameters given fail that test * @throws RepositoryException if the operation otherwise fails */ public ArithmeticOperand divide( DynamicOperand left, DynamicOperand right ) throws InvalidQueryException, RepositoryException; ... }