in subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/GinqAstWalker.groovy [672:834]
MethodCallExpression visitSelectExpression(SelectExpression selectExpression) {
getCurrentGinqExpression().putNodeMetaData(__VISITING_SELECT, true)
Expression selectMethodReceiver = selectExpression.getNodeMetaData(__METHOD_CALL_RECEIVER)
DataSourceExpression dataSourceExpression = selectExpression.dataSourceExpression
Expression projectionExpr = selectExpression.getProjectionExpr()
List<Expression> expressionList = ((TupleExpression) projectionExpr).getExpressions()
validateGroupCols(expressionList)
boolean hasRnVariable = false
boolean hasOverMethodCallExpression = false
projectionExpr.visit(new GinqAstBaseVisitor() {
@Override
void visitVariableExpression(VariableExpression expression) {
if (_RN == expression.text) {
hasRnVariable = true
}
super.visitVariableExpression(expression)
}
@Override
void visitMethodCallExpression(MethodCallExpression call) {
if (isOverMethodCall(call)) {
hasOverMethodCallExpression = true
} else {
super.visitMethodCallExpression(call)
}
}
})
final boolean enableCount = !hasRnVariable && hasOverMethodCallExpression
Expression lambdaCode = expressionList.get(0)
def expressionListSize = expressionList.size()
if (expressionListSize > 1 || (expressionListSize == 1 && lambdaCode instanceof CastExpression)) {
ConstructorCallExpression namedListCtorCallExpression = constructNamedRecordCtorCallExpression(expressionList, MD_SELECT_NAME_LIST)
lambdaCode = namedListCtorCallExpression
}
final boolean parallel = isParallel()
final VariableExpression supplyAsyncLambdaParam = varX(supplyAsyncLambdaParamName)
lambdaCode = ((ListExpression) new ListExpression(Collections.singletonList(lambdaCode)).transformExpression(new ExpressionTransformer() {
@Override
Expression transform(Expression expression) {
if (expression instanceof VariableExpression) {
if (_RN == expression.text) {
getCurrentGinqExpression().putNodeMetaData(__RN_USED, true)
return parallel ? supplyAsyncLambdaParam : callX(varX(getRowNumberName()), 'get')
}
}
if (expression instanceof AbstractGinqExpression) {
return callX(
classX(QUERYABLE_HELPER_TYPE), "singleValue",
visit((AbstractGinqExpression) expression)
)
}
if (expression instanceof MethodCallExpression) {
if (isOverMethodCall(expression)) {
if (expression.objectExpression instanceof MethodCallExpression) {
VariableExpression wqVar = varX(getWindowQueryableName())
String lambdaParamName = getLambdaParamName(dataSourceExpression, lambdaCode)
VariableExpression currentRecordVar = varX(lambdaParamName)
getCurrentGinqExpression().putNodeMetaData(__VISITING_WINDOW_FUNCTION, true)
def windowFunctionMethodCallExpression = (MethodCallExpression) expression.objectExpression
Expression result = null
if (windowFunctionMethodCallExpression.methodAsString in WINDOW_FUNCTION_LIST) {
def argumentListExpression = (ArgumentListExpression) windowFunctionMethodCallExpression.arguments
List<Expression> argumentExpressionList = []
if (windowFunctionMethodCallExpression.methodAsString !in [FUNCTION_ROW_NUMBER, FUNCTION_RANK, FUNCTION_DENSE_RANK, FUNCTION_PERCENT_RANK, FUNCTION_CUME_DIST] && argumentListExpression.expressions) {
def windowFunctionLambdaCode = argumentListExpression.getExpression(0)
def windowFunctionLambdaName = '__wfp'
def rootObjectExpression = findRootObjectExpression(windowFunctionLambdaCode)
windowFunctionLambdaCode = ((ListExpression) (new ListExpression(Collections.singletonList(windowFunctionLambdaCode)).transformExpression(new ExpressionTransformer() {
@Override
Expression transform(Expression expr) {
if (expr instanceof VariableExpression) {
def isJoin = dataSourceExpression instanceof JoinExpression
if (rootObjectExpression.text == expr.text) {
if (isJoin) {
windowFunctionLambdaName = getLambdaParamName(dataSourceExpression, expr)
return correctVars(dataSourceExpression, windowFunctionLambdaName, expr)
}
return varX(windowFunctionLambdaName)
} else if (FUNCTION_AGG == windowFunctionMethodCallExpression.methodAsString && _G == expr.text) {
if (isJoin) {
windowFunctionLambdaName = getLambdaParamName(dataSourceExpression, expr)
}
return callX(
classX(QUERYABLE_HELPER_TYPE),
"navigate",
args(varX(windowFunctionLambdaName), getMetaDataMethodCall(MD_ALIAS_NAME_LIST))
)
}
}
return expr.transformExpression(this)
}
}))).getExpression(0)
if (windowFunctionMethodCallExpression.methodAsString in [FUNCTION_NTILE]) {
argumentExpressionList << argumentListExpression.getExpression(0)
} else {
argumentExpressionList << lambdaX(
params(param(dynamicType(), windowFunctionLambdaName)),
block(stmt(windowFunctionLambdaCode))
)
}
if (windowFunctionMethodCallExpression.methodAsString in [FUNCTION_LEAD, FUNCTION_LAG, FUNCTION_NTH_VALUE]) {
List<Expression> exprList = argumentListExpression.getExpressions()
if (exprList.size() > 1) {
argumentExpressionList.addAll(exprList.subList(1, exprList.size()))
}
}
}
def windowDefinitionFactoryMethodCallExpression = constructWindowDefinitionFactoryMethodCallExpression(expression, dataSourceExpression)
Expression newObjectExpression = callX(wqVar, 'over', args(
callX(TUPLE_TYPE, 'tuple', args(currentRecordVar, parallel ? supplyAsyncLambdaParam : getRowNumberMethodCall())),
windowDefinitionFactoryMethodCallExpression
))
result = callX(
newObjectExpression,
windowFunctionMethodCallExpression.methodAsString,
args(argumentExpressionList)
)
} else {
collectSyntaxError(new GinqSyntaxError(
"Unsupported window function: `${windowFunctionMethodCallExpression.methodAsString}`",
windowFunctionMethodCallExpression.getLineNumber(), windowFunctionMethodCallExpression.getColumnNumber()
))
}
getCurrentGinqExpression().putNodeMetaData(__VISITING_WINDOW_FUNCTION, false)
return result
}
}
}
return expression.transformExpression(this)
}
})).getExpression(0)
List<Expression> extra = []
if (enableCount || rowNumberUsed) {
getCurrentGinqExpression().putNodeMetaData(__RN_USED, true)
extra << callX(varX(rowNumberName), 'getAndIncrement')
}
def selectMethodCallExpression = callXWithLambda(selectMethodReceiver, "select", dataSourceExpression, parallel, lambdaCode, extra, param(dynamicType(), getWindowQueryableName()))
getCurrentGinqExpression().putNodeMetaData(__VISITING_SELECT, false)
return selectMethodCallExpression
}