[dna-commits] DNA SVN: r1326 - trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Tue Nov 17 18:21:38 EST 2009


Author: rhauch
Date: 2009-11-17 18:21:38 -0500 (Tue, 17 Nov 2009)
New Revision: 1326

Modified:
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/FullTextSearchParser.java
   trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/SqlQueryParser.java
Log:
DNA-467 Documented the SQL and full-text search grammars in the JavaDoc for each parser.

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/FullTextSearchParser.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/FullTextSearchParser.java	2009-11-17 21:09:49 UTC (rev 1325)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/FullTextSearchParser.java	2009-11-17 23:21:38 UTC (rev 1326)
@@ -38,6 +38,24 @@
 /**
  * A {@link QueryParser} implementation that parses a full-text search expression. This grammar is based on the full-text search
  * grammar as defined by the JCR 2.0 specification.
+ * <p>
+ * </p>
+ * <h3>Grammar</h3>
+ * <p>
+ * The grammar for the full-text expression is taken from the JCR 2.0 specification, and is as follows:
+ * </p>
+ * 
+ * <pre>
+ * FulltextSearch ::= Disjunct {Space 'OR' Space Disjunct}
+ * Disjunct ::= Term {Space Term}
+ * Term ::= ['-'] SimpleTerm
+ * SimpleTerm ::= Word | '&quot;' Word {Space Word} '&quot;'
+ * Word ::= NonSpaceChar {NonSpaceChar}
+ * Space ::= SpaceChar {SpaceChar}
+ * NonSpaceChar ::= Char - SpaceChar /* Any Char except SpaceChar &#42;/
+ * SpaceChar ::= ' '
+ * Char ::= /* Any character &#42;/
+ * </pre>
  */
 public class FullTextSearchParser {
 

Modified: trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/SqlQueryParser.java
===================================================================
--- trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/SqlQueryParser.java	2009-11-17 21:09:49 UTC (rev 1325)
+++ trunk/dna-graph/src/main/java/org/jboss/dna/graph/query/parse/SqlQueryParser.java	2009-11-17 23:21:38 UTC (rev 1326)
@@ -97,13 +97,342 @@
 /**
  * A {@link QueryParser} implementation that parses a subset of SQL select and set queries.
  * <p>
- * This grammar is based on the SQL grammar as defined by the JCR 2.0 specification, with some useful additions:
+ * This grammar is equivalent to the SQL grammar as defined by the JCR 2.0 specification, with some useful additions:
  * <ul>
- * <li>(UNION|INTERSECT|EXCEPT) [ALL]</li>
- * <li>SELECT DISTINCT</li>
- * <li>LIMIT clauses</li>
+ * <li>"<code>... (UNION|INTERSECT|EXCEPT) [ALL] ...</code>" to combine and merge results from multiple queries</li>
+ * <li>"<code>SELECT DISTINCT ...</code>" to remove duplicates</li>
+ * <li>"<code>LIMIT count [OFFSET number]</code>" clauses to control the number of results returned as well as the number of rows
+ * that should be skipped</li>
+ * <li>Support for additional join types, including "<code>FULL OUTER JOIN</code>" and "<code>CROSS JOIN</code>"</li>
+ * <li>Additional dynamic operands "<code>DEPTH([&lt;selectorName>])</code>" and "<code>PATH([&lt;selectorName>])</code>" that
+ * enables placing constraints on the node depth and path, respectively, and which can be used in a manner similar to "
+ * <code>NAME([&lt;selectorName>])</code>" and "<code>LOCALNAME([&lt;selectorName>])</code>. Note in each of these cases, the
+ * selector name is optional if there is only one selector in the query. on the node depth</li>
+ * <li>Support for the IN clause and NOT IN clause to more easily supply a list of valid discrete static operands: "
+ * <code>&lt;dynamicOperand> [NOT] IN (&lt;staticOperand> {, &lt;staticOperand>})</code>"</li>
+ * <li>Support for the BETWEEN clause: "<code>&lt;dynamicOperand> [NOT] BETWEEN &lt;lowerBoundStaticOperand> [EXCLUSIVE] AND
+ * &lt;upperBoundStaticOperand> [EXCLUSIVE]</code>"</i>
  * </ul>
  * </p>
+ * <h3>SQL grammar</h3>
+ * <p>
+ * This section defines the complete grammar for the SQL dialect supported by this parser.
+ * </p>
+ * <h4>Queries</h4>
+ * 
+ * <pre>
+ * QueryCommand ::= Query | SetQuery
+ * 
+ * SetQuery ::= Query ('UNION'|'INTERSECT'|'EXCEPT') [ALL] Query
+ *                  { ('UNION'|'INTERSECT'|'EXCEPT') [ALL] Query }
+ * 
+ * Query ::= 'SELECT' ['DISINCT'] columns
+ *           'FROM' Source
+ *           ['WHERE' Constraint]
+ *           ['ORDER BY' orderings]
+ *           [Limit]
+ * </pre>
+ * 
+ * <h4>Sources</h4>
+ * 
+ * <pre>
+ * Source ::= Selector | Join
+ * 
+ * Selector ::= nodeTypeName ['AS' selectorName]
+ * 
+ * nodeTypeName ::= Name
+ * </pre>
+ * 
+ * <h4>Joins</h4>
+ * 
+ * <pre>
+ * Join ::= left [JoinType] 'JOIN' right 'ON' JoinCondition
+ *          // If JoinType is omitted INNER is assumed.
+ *          
+ * left ::= Source
+ * right ::= Source
+ * 
+ * JoinType ::= Inner | LeftOuter | RightOuter | FullOuter | Cross
+ * 
+ * Inner ::= 'INNER' ['JOIN']
+ * 
+ * LeftOuter ::= 'LEFT JOIN' | 'OUTER JOIN' | 'LEFT OUTER JOIN'
+ * 
+ * RightOuter ::= 'RIGHT OUTER' ['JOIN']
+ * 
+ * RightOuter ::= 'FULL OUTER' ['JOIN']
+ * 
+ * RightOuter ::= 'CROSS' ['JOIN']
+ * 
+ * JoinCondition ::= EquiJoinCondition | SameNodeJoinCondition | ChildNodeJoinCondition | DescendantNodeJoinCondition
+ * </pre>
+ * 
+ * <h5>Equi-join conditions</h5>
+ * 
+ * <pre>
+ * EquiJoinCondition ::= selector1Name'.'property1Name '=' selector2Name'.'property2Name
+ * 
+ * selector1Name ::= selectorName
+ * selector2Name ::= selectorName
+ * property1Name ::= propertyName
+ * property2Name ::= propertyName
+ * </pre>
+ * 
+ * <h5>Same-node join condition</h5>
+ * 
+ * <pre>
+ * SameNodeJoinCondition ::= 'ISSAMENODE(' selector1Name ',' selector2Name [',' selector2Path] ')'
+ * 
+ * selector2Path ::= Path
+ * </pre>
+ * 
+ * <h5>Child-node join condition</h5>
+ * 
+ * <pre>
+ * ChildNodeJoinCondition ::= 'ISCHILDNODE(' childSelectorName ',' parentSelectorName ')'
+ * 
+ * childSelectorName ::= selectorName
+ * parentSelectorName ::= selectorName
+ * </pre>
+ * 
+ * <h5>Descendant-node join condition</h5>
+ * 
+ * <pre>
+ * DescendantNodeJoinCondition ::= 'ISDESCENDANTNODE(' descendantSelectorName ',' ancestorSelectorName ')'
+ * descendantSelectorName ::= selectorName
+ * ancestorSelectorName ::= selectorName
+ * </pre>
+ * 
+ * <h4>Constraints</h4>
+ * 
+ * <pre>
+ * Constraint ::= ConstraintItem | '(' ConstraintItem ')'
+ * 
+ * ConstraintItem ::= And | Or | Not | Comparison | Between | PropertyExistence | SetConstraint | FullTextSearch | 
+ *                    SameNode | ChildNode | DescendantNode
+ * </pre>
+ * 
+ * <h5>And constraint</h5>
+ * 
+ * <pre>
+ * And ::= constraint1 'AND' constraint2
+ * 
+ * constraint1 ::= Constraint
+ * constraint2 ::= Constraint
+ * </pre>
+ * 
+ * <h5>Or constraint</h5>
+ * 
+ * <pre>
+ * Or ::= constraint1 'OR' constraint2
+ * </pre>
+ * 
+ * <h5>Not constraint</h5>
+ * 
+ * <pre>
+ * Not ::= 'NOT' Constraint
+ * </pre>
+ * 
+ * <h5>Comparison constraint</h5>
+ * 
+ * <pre>
+ * Comparison ::= DynamicOperand Operator StaticOperand
+ * 
+ * Operator ::= '=' | '!=' | '<' | '<=' | '>' | '>=' | 'LIKE'
+ * </pre>
+ * 
+ * <h5>Between constraint</h5>
+ * 
+ * <pre>
+ * Between ::= DynamicOperand ['NOT'] 'BETWEEN' lowerBound ['EXCLUSIVE'] 'AND' upperBound ['EXCLUSIVE']
+ * 
+ * lowerBound ::= StaticOperand
+ * upperBound ::= StaticOperand
+ * </pre>
+ * 
+ * <h5>Property existence constraint</h5>
+ * 
+ * <pre>
+ * PropertyExistence ::= selectorName'.'propertyName 'IS' ['NOT'] 'NULL' | 
+ *                       propertyName 'IS' ['NOT'] 'NULL' &#47;* If only one selector exists in this query *&#47;
+ * 
+ * </pre>
+ * 
+ * <h5>Set constraint</h5>
+ * 
+ * <pre>
+ * SetConstraint ::= selectorName'.'propertyName ['NOT'] 'IN' | 
+ *                       propertyName ['NOT'] 'IN' &#47;* If only one selector exists in this query *&#47;
+ *                       '(' firstStaticOperand {',' additionalStaticOperand } ')'
+ * firstStaticOperand ::= StaticOperand
+ * additionalStaticOperand ::= StaticOperand
+ * </pre>
+ * 
+ * <h5>Full-text search constraint</h5>
+ * 
+ * <pre>
+ * FullTextSearch ::= 'CONTAINS(' ([selectorName'.']propertyName | selectorName'.*') 
+ *                            ',' ''' fullTextSearchExpression''' ')'
+ *                    &#47;* If only one selector exists in this query, explicit specification of the selectorName
+ *                       preceding the propertyName is optional *&#47;
+ * fullTextSearchExpression ::= &#47;* a full-text search expression, see {@link FullTextSearchParser} *&#47;
+ * </pre>
+ * 
+ * <h5>Same-node constraint</h5>
+ * 
+ * <pre>
+ * SameNode ::= 'ISSAMENODE(' [selectorName ','] Path ')' 
+ *                    &#47;* If only one selector exists in this query, explicit specification of the selectorName
+ *                       preceding the propertyName is optional *&#47;
+ * </pre>
+ * 
+ * <h5>Child-node constraint</h5>
+ * 
+ * <pre>
+ * ChildNode ::= 'ISCHILDNODE(' [selectorName ','] Path ')' 
+ *                    &#47;* If only one selector exists in this query, explicit specification of the selectorName
+ *                       preceding the propertyName is optional *&#47;
+ * </pre>
+ * 
+ * <h5>Descendant-node constraint</h5>
+ * 
+ * <pre>
+ * DescendantNode ::= 'ISDESCENDANTNODE(' [selectorName ','] Path ')' 
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       preceding the propertyName is optional *&#47;
+ * </pre>
+ * 
+ * <h5>Paths and names</h5>
+ * 
+ * <pre>
+ * 
+ * Name ::= '[' quotedName ']' | '[' simpleName ']' | simpleName
+ * 
+ * quotedName ::= /* A JCR Name (see the JCR specification) *&#47;
+ * simpleName ::= /* A JCR Name that contains only SQL-legal characters (namely letters, digits, and underscore) *&#47;
+ *
+ * Path ::= '[' quotedPath ']' | '[' simplePath ']' | simplePath
+ *
+ * quotedPath ::= /* A JCR Path that contains non-SQL-legal characters *&#47;
+ * simplePath ::= /* A JCR Path (rather Name) that contains only SQL-legal characters (namely letters, digits, and underscore) *&#47;
+ * </pre>
+ * 
+ * <h4>Static operands</h4>
+ * 
+ * <pre>
+ * StaticOperand ::= Literal | BindVariableValue
+ * </pre>
+ * 
+ * <h5>Literal</h5>
+ * 
+ * <pre>
+ * Literal ::= CastLiteral | UncastLiteral
+ * 
+ * CastLiteral ::= 'CAST(' UncastLiteral ' AS ' PropertyType ')'
+ * 
+ * PropertyType ::= 'STRING' | 'BINARY' | 'DATE' | 'LONG' | 'DOUBLE' | 'DECIMAL' | 'BOOLEAN' | 'NAME' | 'PATH' | 
+ *                  'REFERENCE' | 'WEAKREFERENCE' | 'URI'
+ *                  /* 'WEAKREFERENCE' is not currently supported in JCR 1.0 *&#47;
+ *                  
+ * UncastLiteral ::= UnquotedLiteral | ''' UnquotedLiteral ''' | '"' UnquotedLiteral '"'
+ * 
+ * UnquotedLiteral ::= /* String form of a JCR Value, as defined in the JCR specification *&#47;
+ * </pre>
+ * 
+ * <h5>Bind variables</h5>
+ * 
+ * <pre>
+ * BindVariableValue ::= '$'bindVariableName
+ * 
+ * bindVariableName ::= /* A string that conforms to the JCR Name syntax, though the prefix does not need to be
+ *                         a registered namespace prefix. *&#47;
+ * </pre>
+ * 
+ * <h4>Dynamic operands</h4>
+ * 
+ * <pre>
+ * DynamicOperand ::= PropertyValue | Length | NodeName | NodeLocalName | NodePath | NodeDepth | 
+ *                    FullTextSearchScore | LowerCase | UpperCase
+ * </pre>
+ * <h5>Property value</h5>
+ * <pre>
+ * PropertyValue ::= [selectorName'.'] propertyName
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       preceding the propertyName is optional *&#47;
+ * </pre>
+ * <h5>Property length</h5>
+ * <pre>
+ * Length ::= 'LENGTH(' PropertyValue ')'
+ * </pre>
+ * <h5>Node name</h5>
+ * <pre>
+ * NodeName ::= 'NAME(' [selectorName] ')'
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       is optional *&#47;
+ * </pre>
+ * <h5>Node local name</h5>
+ * <pre>
+ * NodeLocalName ::= 'LOCALNAME(' [selectorName] ')'
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       is optional *&#47;
+ * </pre>
+ * <h5>Node path</h5>
+ * <pre>
+ * NodePath ::= 'PATH(' [selectorName] ')'
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       is optional *&#47;
+ * </pre>
+ * <h5>Node depth</h5>
+ * <pre>
+ * NodeDepth ::= 'DEPTH(' [selectorName] ')'
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       is optional *&#47;
+ * </pre>
+ * <h5>Full-text search score</h5>
+ * <pre>
+ * FullTextSearchScore ::= 'SCORE(' [selectorName] ')'
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       is optional *&#47;
+ * </pre>
+ * <h5>Lowercase</h5>
+ * <pre>
+ * LowerCase ::= 'LOWER(' DynamicOperand ')'
+ * </pre>
+ * <h5>Uppercase</h5>
+ * <pre>
+ * UpperCase ::= 'UPPER(' DynamicOperand ')'
+ * </pre>
+ * 
+ * <h4>Ordering</h4>
+ * 
+ * <pre>
+ * orderings ::= Ordering {',' Ordering}
+ * 
+ * Ordering ::= DynamicOperand [Order]
+ * 
+ * Order ::= 'ASC' | 'DESC'
+ * </pre>
+ * 
+ * <h4>Columns</h4>
+ * 
+ * <pre>
+ * columns ::= (Column ',' {Column}) | '*'
+ * 
+ * Column ::= ([selectorName'.']propertyName ['AS' columnName]) | (selectorName'.*')
+ *                    /* If only one selector exists in this query, explicit specification of the selectorName
+ *                       preceding the propertyName is optional *&#47;
+ * selectorName ::= Name
+ * propertyName ::= Name
+ * columnName ::= Name
+ * </pre>
+ * 
+ * <h4>Limit</h4>
+ * 
+ * <pre>
+ * Limit ::= 'LIMIT' count [ 'OFFSET' offset ]
+ * count ::= /* Positive integer value *&#47;
+ * offset ::= /* Non-negative integer value *&#47;
+ * </pre>
  */
 public class SqlQueryParser implements QueryParser {
 
@@ -255,11 +584,11 @@
             } else if (tokens.canConsume("OUTER", "JOIN") || tokens.canConsume("LEFT", "JOIN")
                        || tokens.canConsume("LEFT", "OUTER", "JOIN")) {
                 joinType = JoinType.LEFT_OUTER;
-            } else if (tokens.canConsume("RIGHT", "OUTER", "JOIN")) {
+            } else if (tokens.canConsume("RIGHT", "OUTER", "JOIN") || tokens.canConsume("RIGHT", "OUTER")) {
                 joinType = JoinType.RIGHT_OUTER;
-            } else if (tokens.canConsume("FULL", "OUTER", "JOIN")) {
+            } else if (tokens.canConsume("FULL", "OUTER", "JOIN") || tokens.canConsume("FULL", "OUTER")) {
                 joinType = JoinType.FULL_OUTER;
-            } else if (tokens.canConsume("CROSS", "JOIN")) {
+            } else if (tokens.canConsume("CROSS", "JOIN") || tokens.canConsume("CROSS")) {
                 joinType = JoinType.CROSS;
             }
             if (joinType == null) break;



More information about the dna-commits mailing list