super(config, argumentHandler);
}
@Override public ColumnExpressions<?> virtualMethodCallValue(MethodCallValue.VirtualMethodCallValue val, SymbExPassDown in) throws TypedValueVisitorException
{
MethodSignature sig = val.getSignature();
if (ScalaMetamodelUtil.newTuple2.equals(sig)
|| ScalaMetamodelUtil.newTuple3.equals(sig)
|| ScalaMetamodelUtil.newTuple4.equals(sig)
|| ScalaMetamodelUtil.newTuple5.equals(sig)
|| ScalaMetamodelUtil.newTuple8.equals(sig))
{
ColumnExpressions<?> [] vals = new ColumnExpressions<?> [val.args.size()];
// TODO: This is a little wonky passing down isExpectingConditional, but I think it's right for those times you create a tuple with booleans and then extract the booleans later
SymbExPassDown passdown = SymbExPassDown.with(val, in.isExpectingConditional);
for (int n = 0; n < vals.length; n++)
vals[n] = val.args.get(n).visit(this, passdown);
RowReader<?> [] valReaders = new RowReader[vals.length];
for (int n = 0; n < vals.length; n++)
valReaders[n] = vals[n].reader;
ColumnExpressions<?> toReturn = new ColumnExpressions<>(ScalaTupleRowReader.createReaderForTuple(sig.owner, valReaders));
for (int n = 0; n < vals.length; n++)
toReturn.columns.addAll(vals[n].columns);
return toReturn;
}
else if (ScalaMetamodelUtil.TUPLE_ACCESSORS.containsKey(sig))
{
int idx = ScalaMetamodelUtil.TUPLE_ACCESSORS.get(sig) - 1;
// TODO: This is a little wonky passing down isExpectingConditional, but I think it's right for those times you create a tuple with booleans and then extract the booleans later
SymbExPassDown passdown = SymbExPassDown.with(val, in.isExpectingConditional);
ColumnExpressions<?> base = val.base.visit(this, passdown);
RowReader<?> subreader = ((ScalaTupleRowReader<?>)base.reader).getReaderForIndex(idx);
ColumnExpressions<?> toReturn = new ColumnExpressions<>(subreader);
int baseOffset = ((ScalaTupleRowReader<?>)base.reader).getColumnForIndex(idx);
for (int n = 0; n < subreader.getNumColumns(); n++)
toReturn.columns.add(base.columns.get(n + baseOffset));
return toReturn;
}
else if (ScalaMetamodelUtil.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)
{
TypedValue arg = val.args.get(0);
if ((arg instanceof LambdaFactory))
{
LambdaFactory lambdaFactory = (LambdaFactory)arg;
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);
}
}
else if (arg instanceof MethodCallValue.VirtualMethodCallValue && ((MethodCallValue.VirtualMethodCallValue)arg).isConstructor())
{
MethodCallValue.VirtualMethodCallValue lambdaConstructor = (MethodCallValue.VirtualMethodCallValue)arg;
try {
Map<String, TypedValue> indirectParamMapping = config.findLambdaAsClassConstructorParameters(lambdaConstructor.getSignature(), lambdaConstructor.args);
lambda = LambdaAnalysis.analyzeClassAsLambda(config.metamodel, config.alternateClassLoader, config.isObjectEqualsSafe, new LambdaAnalysis.LambdaAsClassAnalysisConfig(), lambdaConstructor.getSignature().getOwnerType().getClassName(), indirectParamMapping, true);
} catch (Exception e)
{
throw new TypedValueVisitorException("Could not analyze the lambda code", e);
}
}
else
throw new TypedValueVisitorException("Expecting a lambda factory for aggregate method");
}
try {
AggregateTransform transform;
if (sig.equals(ScalaMetamodelUtil.streamSumInt)
|| sig.equals(ScalaMetamodelUtil.streamSumLong)
|| sig.equals(ScalaMetamodelUtil.streamSumDouble)
|| sig.equals(ScalaMetamodelUtil.streamSumBigDecimal)
|| sig.equals(ScalaMetamodelUtil.streamSumBigInteger))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.SUM);
else if (sig.equals(ScalaMetamodelUtil.streamMax))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.MAX);
else if (sig.equals(ScalaMetamodelUtil.streamMin))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.MIN);
else if (sig.equals(ScalaMetamodelUtil.streamAvg))
transform = new AggregateTransform(config, AggregateTransform.AggregateType.AVG);
else if (sig.equals(ScalaMetamodelUtil.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(ScalaMetamodelUtil.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 (sig.equals(ScalaMetamodelUtil.STRINGBUILDER_STRING))
{
List<ColumnExpressions<?>> concatenatedStrings = new ArrayList<>();
MethodCallValue.VirtualMethodCallValue baseVal = val;
while (true)
{