Skip to content

Feature/count expression #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion exist-core/src/main/antlr/org/exist/xquery/parser/XQuery.g
Original file line number Diff line number Diff line change
Expand Up @@ -804,14 +804,21 @@ initialClause throws XPathException

intermediateClause throws XPathException
:
( initialClause | whereClause | groupByClause | orderByClause )
( initialClause | whereClause | groupByClause | orderByClause | countClause )
;

whereClause throws XPathException
:
"where"^ exprSingle
;

countClause throws XPathException
{ String varName; }
:
"count"^ DOLLAR! varName=varName!
{ #countClause = #(#countClause, #[VARIABLE_BINDING, varName]); }
;

forClause throws XPathException
:
"for"^ inVarBinding ( COMMA! inVarBinding )*
Expand Down Expand Up @@ -2224,6 +2231,8 @@ reservedKeywords returns [String name]
"map" { name = "map"; }
|
"array" { name = "array"; }
|
"count" { name = "count"; }
;

/**
Expand Down
16 changes: 16 additions & 0 deletions exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,19 @@ throws PermissionDeniedException, EXistException, XPathException
clauses.add(clause);
}
)
|
#(
co:"count"
countVarName:VARIABLE_BINDING
{
ForLetClause clause = new ForLetClause();
clause.ast = co;
clause.varName = countVarName.getText();
clause.type = FLWORClause.ClauseType.COUNT;
clause.inputSequence = null;
clauses.add(clause);
}
)
)+
step=expr [(PathExpr) action]
{
Expand All @@ -1728,6 +1741,9 @@ throws PermissionDeniedException, EXistException, XPathException
case WHERE:
expr = new WhereClause(context, new DebuggableExpression(clause.inputSequence));
break;
case COUNT:
expr = new CountClause(context, clause.varName);
break;
default:
expr= new ForExpr(context, clause.allowEmpty);
break;
Expand Down
52 changes: 52 additions & 0 deletions exist-core/src/main/java/org/exist/xquery/CountClause.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

package org.exist.xquery;

import org.exist.dom.persistent.*;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.Type;

/**
* Implements a count clause inside a FLWOR expressions.
*
* @author
*/
public class CountClause extends AbstractFLWORClause {

protected String varName;

public CountClause(XQueryContext context, String countName) {
super(context);
this.varName = countName;
}

@Override
public ClauseType getType() {
return ClauseType.COUNT;
}

public String getVarName() {
return varName;
}

@Override
public void analyze(AnalyzeContextInfo contextInfo) throws XPathException
{

}

@Override
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException
{
return null;
}

@Override
public void dump(ExpressionDumper dumper) {
dumper.display("count", this.getLine());
dumper.startIndent();
dumper.display(this.varName);
dumper.endIndent().nl();
}
}
2 changes: 1 addition & 1 deletion exist-core/src/main/java/org/exist/xquery/FLWORClause.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
public interface FLWORClause extends Expression {

enum ClauseType {
FOR, LET, GROUPBY, ORDERBY, WHERE, SOME, EVERY
FOR, LET, GROUPBY, ORDERBY, WHERE, SOME, EVERY, COUNT
}

/**
Expand Down
71 changes: 71 additions & 0 deletions exist-core/src/test/java/org/exist/xquery/CountExpressionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.exist.xquery;

import antlr.RecognitionException;
import antlr.TokenStreamException;
import antlr.collections.AST;
import org.exist.EXistException;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
import org.exist.test.ExistEmbeddedServer;
import org.exist.xquery.parser.XQueryAST;
import org.exist.xquery.parser.XQueryLexer;
import org.exist.xquery.parser.XQueryParser;
import org.exist.xquery.parser.XQueryTreeParser;
import org.junit.ClassRule;
import org.junit.Test;

import java.io.StringReader;

import static org.junit.Assert.*;

public class CountExpressionTest
{

@ClassRule
public static final ExistEmbeddedServer existEmbeddedServer = new ExistEmbeddedServer(true, true);

@Test
public void countTest() throws EXistException, RecognitionException, XPathException, TokenStreamException
{
String query = "xquery version \"3.1\";\n" +
"for $p in $products\n" +
"order by $p/sales descending\n" +
"count $rank\n" +
"where $rank <= 3\n" +
"return\n" +
" <product rank=\"{$rank}\">\n" +
" {$p/name, $p/sales}\n" +
" </product>";

BrokerPool pool = BrokerPool.getInstance();
try(final DBBroker broker = pool.getBroker()) {
// parse the query into the internal syntax tree
XQueryContext context = new XQueryContext(broker.getBrokerPool());
XQueryLexer lexer = new XQueryLexer(context, new StringReader(query));
XQueryParser xparser = new XQueryParser(lexer);
xparser.xpath();
if (xparser.foundErrors()) {
fail(xparser.getErrorMessage());
return;
}

XQueryAST ast = (XQueryAST) xparser.getAST();

XQueryTreeParser treeParser = new XQueryTreeParser(context);
PathExpr expr = new PathExpr(context);
treeParser.xpath(ast, expr);
if (treeParser.foundErrors()) {
fail(treeParser.getErrorMessage());
return;
}

// count keyword
assertEquals(XQueryParser.LITERAL_count, ast.getNextSibling().getFirstChild().getNextSibling().getNextSibling().getType());
// rank variable binding
assertEquals(XQueryParser.VARIABLE_BINDING, ast.getNextSibling().getFirstChild().getNextSibling().getNextSibling().getFirstChild().getType());
assertTrue(((ForExpr)expr.getFirst()).returnExpr instanceof OrderByClause);
assertTrue(((OrderByClause)(((ForExpr)expr.getFirst()).returnExpr)).returnExpr instanceof CountClause);
assertEquals("rank", ((CountClause)((OrderByClause)(((ForExpr)expr.getFirst()).returnExpr)).returnExpr).varName);
}
}
}