else if (sig.equals(TransformationClassAnalyzer.newBigDecimalLong)
|| sig.equals(TransformationClassAnalyzer.newBigDecimalDouble)
|| sig.equals(TransformationClassAnalyzer.newBigDecimalInt)
|| sig.equals(TransformationClassAnalyzer.newBigDecimalBigInteger))
{
throw new TypedValueVisitorException("New BigDecimals can only be created in the context of numeric promotion");
}
else if (isAggregateMethod(sig))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
// Check out what stream we're aggregating
SymbExToSubQuery translator = config.newSymbExToSubQuery(argHandler);
JPQLQuery<?> subQuery = val.base.visit(translator, passdown);
// Extract the lambda used
LambdaAnalysis lambda = null;
if (val.args.size() > 0)
{
if (!(val.args.get(0) instanceof LambdaFactory))
throw new TypedValueVisitorException("Expecting a lambda factory for aggregate method");
LambdaFactory lambdaFactory = (LambdaFactory)val.args.get(0);
try {
lambda = LambdaAnalysis.analyzeMethod(config.metamodel, config.alternateClassLoader, config.isObjectEqualsSafe, lambdaFactory.getLambdaMethod(), lambdaFactory.getCapturedArgs(), true);
} catch (Exception e)
{
throw new TypedValueVisitorException("Could not analyze the lambda code", e);
}
}
try {
AggregateTransform transform;
if (sig.equals(MethodChecker.streamSumInt)
|| sig.equals(MethodChecker.streamSumLong)
|| sig.equals(MethodChecker.streamSumDouble)
|| sig.equals(MethodChecker.streamSumBigDecimal)
|| sig.equals(MethodChecker.streamSumBigInteger))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.SUM);
else if (sig.equals(MethodChecker.streamMax))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.MAX);
else if (sig.equals(MethodChecker.streamMin))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.MIN);
else if (sig.equals(MethodChecker.streamAvg))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.AVG);
else if (sig.equals(MethodChecker.streamCount))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.COUNT);
else
throw new TypedValueVisitorException("Unhandled aggregate operation");
JPQLQuery<?> aggregatedQuery = transform.apply(subQuery, lambda, argHandler);
// Return the aggregated columns that we've now calculated
if (aggregatedQuery.getClass() == SelectOnly.class)
{
SelectOnly<?> select = (SelectOnly<?>)aggregatedQuery;
return select.cols;
}
else if (aggregatedQuery.isValidSubquery() && aggregatedQuery instanceof SelectFromWhere)
{
SelectFromWhere<?> sfw = (SelectFromWhere<?>)aggregatedQuery;
ColumnExpressions<?> toReturn = new ColumnExpressions<>(sfw.cols.reader);
for (Expression col: sfw.cols.columns)
{
SelectFromWhere<?> oneColQuery = sfw.shallowCopy();
oneColQuery.cols = ColumnExpressions.singleColumn(new SimpleRowReader<>(), col);
toReturn.columns.add(SubqueryExpression.from(oneColQuery));
}
return toReturn;
}
else
{
throw new TypedValueVisitorException("Unknown subquery type");
}
} catch (QueryTransformException e)
{
throw new TypedValueVisitorException("Could not derive an aggregate function for a lambda", e);
}
}
else if (sig.equals(MethodChecker.streamGetOnlyValue))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
// Check out what stream we're aggregating
SymbExToSubQuery translator = config.newSymbExToSubQuery(argHandler);
JPQLQuery<?> subQuery = val.base.visit(translator, passdown);
if (subQuery.isValidSubquery() && subQuery instanceof SelectFromWhere)
{
SelectFromWhere<?> sfw = (SelectFromWhere<?>)subQuery;
ColumnExpressions<?> toReturn = new ColumnExpressions<>(sfw.cols.reader);
for (Expression col: sfw.cols.columns)
{
SelectFromWhere<?> oneColQuery = sfw.shallowCopy();
oneColQuery.cols = ColumnExpressions.singleColumn(new SimpleRowReader<>(), col);
toReturn.columns.add(SubqueryExpression.from(oneColQuery));
}
return toReturn;
}
throw new TypedValueVisitorException("Cannot apply getOnlyValue() to the given subquery");
}
else if (MethodChecker.jpqlFunctionMethods.contains(sig))
{
if (sig.equals(MethodChecker.bigDecimalAbs)
|| sig.equals(MethodChecker.bigIntegerAbs))
{
SymbExPassDown passdown = SymbExPassDown.with(val, in.isExpectingConditional);
ColumnExpressions<?> base = val.base.visit(this, passdown);
return ColumnExpressions.singleColumn(base.reader,
FunctionExpression.singleParam("ABS", base.getOnlyColumn()));
}
else if (sig.equals(MethodChecker.stringToUpper))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
ColumnExpressions<?> base = val.base.visit(this, passdown);
return ColumnExpressions.singleColumn(base.reader,
FunctionExpression.singleParam("UPPER", base.getOnlyColumn()));
}
else if (sig.equals(MethodChecker.stringToLower))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
ColumnExpressions<?> base = val.base.visit(this, passdown);
return ColumnExpressions.singleColumn(base.reader,
FunctionExpression.singleParam("LOWER", base.getOnlyColumn()));
}
else if (sig.equals(MethodChecker.stringLength))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
ColumnExpressions<?> base = val.base.visit(this, passdown);
return ColumnExpressions.singleColumn(base.reader,
FunctionExpression.singleParam("LENGTH", base.getOnlyColumn()));
}
else if (sig.equals(MethodChecker.stringTrim))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
ColumnExpressions<?> base = val.base.visit(this, passdown);
return ColumnExpressions.singleColumn(base.reader,
FunctionExpression.singleParam("TRIM", base.getOnlyColumn()));
}
else if (sig.equals(MethodChecker.stringSubstring))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
ColumnExpressions<?> base = val.base.visit(this, passdown);
ColumnExpressions<?> startIndex = val.args.get(0).visit(this, passdown);
ColumnExpressions<?> endIndex = val.args.get(1).visit(this, passdown);
return ColumnExpressions.singleColumn(base.reader,
FunctionExpression.threeParam("SUBSTRING",
base.getOnlyColumn(),
new BinaryExpression("+", startIndex.getOnlyColumn(), new ConstantExpression("1")),
new BinaryExpression("-", endIndex.getOnlyColumn(), startIndex.getOnlyColumn())));
}
else if (sig.equals(MethodChecker.stringIndexOf))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
ColumnExpressions<?> base = val.base.visit(this, passdown);
ColumnExpressions<?> search = val.args.get(0).visit(this, passdown);
return ColumnExpressions.singleColumn(base.reader,
new BinaryExpression("-",
FunctionExpression.twoParam("LOCATE",
search.getOnlyColumn(),
base.getOnlyColumn())
, new ConstantExpression("1")));
}
throw new TypedValueVisitorException("Do not know how to translate the method " + sig + " into a JPQL function");
}
else if (sig.equals(TransformationClassAnalyzer.stringBuilderToString))
{
List<ColumnExpressions<?>> concatenatedStrings = new ArrayList<>();
MethodCallValue.VirtualMethodCallValue baseVal = val;
while (true)
{
if (!(baseVal.base instanceof MethodCallValue.VirtualMethodCallValue))
throw new TypedValueVisitorException("Unexpected use of StringBuilder");
baseVal = (MethodCallValue.VirtualMethodCallValue)baseVal.base;
if (baseVal.getSignature().equals(TransformationClassAnalyzer.newStringBuilderString))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
concatenatedStrings.add(baseVal.args.get(0).visit(this, passdown));
break;
}
else if (baseVal.getSignature().equals(TransformationClassAnalyzer.newStringBuilder))
{
break;
}
else if (baseVal.getSignature().equals(TransformationClassAnalyzer.stringBuilderAppendString))
{
SymbExPassDown passdown = SymbExPassDown.with(val, false);
concatenatedStrings.add(baseVal.args.get(0).visit(this, passdown));
}
else
throw new TypedValueVisitorException("Unexpected use of StringBuilder");
}
if (concatenatedStrings.size() == 1)
return concatenatedStrings.get(0);
Expression head = concatenatedStrings.get(concatenatedStrings.size() - 1).getOnlyColumn();