Package org.jinq.jpa.transform

Source Code of org.jinq.jpa.transform.SymbExToSubQuery

package org.jinq.jpa.transform;

import org.jinq.jpa.jpqlquery.ColumnExpressions;
import org.jinq.jpa.jpqlquery.Expression;
import org.jinq.jpa.jpqlquery.From;
import org.jinq.jpa.jpqlquery.FromAliasExpression;
import org.jinq.jpa.jpqlquery.JPQLQuery;
import org.jinq.jpa.jpqlquery.ReadFieldExpression;
import org.jinq.jpa.jpqlquery.SelectFromWhere;
import org.jinq.jpa.jpqlquery.SimpleRowReader;
import org.objectweb.asm.Type;

import ch.epfl.labos.iu.orm.queryll2.path.TransformationClassAnalyzer;
import ch.epfl.labos.iu.orm.queryll2.symbolic.ConstantValue;
import ch.epfl.labos.iu.orm.queryll2.symbolic.LambdaFactory;
import ch.epfl.labos.iu.orm.queryll2.symbolic.MethodCallValue;
import ch.epfl.labos.iu.orm.queryll2.symbolic.MethodSignature;
import ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValue;
import ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValueVisitor;
import ch.epfl.labos.iu.orm.queryll2.symbolic.TypedValueVisitorException;

public class SymbExToSubQuery extends TypedValueVisitor<SymbExPassDown, JPQLQuery<?>, TypedValueVisitorException>
{
   final SymbExArgumentHandler argHandler;
   JPQLQueryTransformConfiguration config = new JPQLQueryTransformConfiguration();

   SymbExToSubQuery(JPQLQueryTransformConfiguration config, SymbExArgumentHandler argumentHandler)
   {
      this.config = config;
      this.argHandler = argumentHandler;
   }
  
   @Override public JPQLQuery<?> defaultValue(TypedValue val, SymbExPassDown in) throws TypedValueVisitorException
   {
      throw new TypedValueVisitorException("Unhandled symbolic execution operation: " + val);
   }

   @Override public JPQLQuery<?> argValue(TypedValue.ArgValue val, SymbExPassDown in) throws TypedValueVisitorException
   {
      int index = val.getIndex();
      return argHandler.handleSubQueryArg(index, val.getType());
   }

   private boolean isStreamMethod(MethodSignature sig)
   {
      return sig.equals(MethodChecker.streamDistinct)
            || sig.equals(MethodChecker.streamSelect)
            || sig.equals(MethodChecker.streamWhere)
            || sig.equals(MethodChecker.streamJoin);
   }
  
   @Override public JPQLQuery<?> virtualMethodCallValue(MethodCallValue.VirtualMethodCallValue val, SymbExPassDown in) throws TypedValueVisitorException
   {
      MethodSignature sig = val.getSignature();
      if (MetamodelUtil.inQueryStream.equals(sig))
      {
         return handleInQueryStreamSource(val.base, val.args.get(0));
      }
      else if (isStreamMethod(sig))
      {
         SymbExPassDown passdown = SymbExPassDown.with(val, false);
        
         // Check out what stream we're aggregating
         JPQLQuery<?> subQuery = val.base.visit(this, 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 {
            JPQLQuery<?> transformedQuery;
            if (sig.equals(MethodChecker.streamDistinct))
            {
               DistinctTransform transform = new DistinctTransform(config);
               transformedQuery = transform.apply(subQuery, argHandler);
            }
            else if (sig.equals(MethodChecker.streamSelect))
            {
               SelectTransform transform = new SelectTransform(config, false);
               transformedQuery = transform.apply(subQuery, lambda, argHandler);
            }
            else if (sig.equals(MethodChecker.streamWhere))
            {
               WhereTransform transform = new WhereTransform(config, false);
               transformedQuery = transform.apply(subQuery, lambda, argHandler);
            }
            else if (sig.equals(MethodChecker.streamJoin))
            {
               JoinTransform transform = new JoinTransform(config, false);
               transformedQuery = transform.apply(subQuery, lambda, argHandler);
            }
            else
               throw new TypedValueVisitorException("Unknown stream operation: " + sig);

            return transformedQuery;
         }
         catch (QueryTransformException e)
         {
            throw new TypedValueVisitorException("Subquery could not be transformed.", e);
         }
//         // Return the aggregated columns that we've now calculated
//         if (transformedQuery.getClass() == SelectOnly.class)
//         {
//            SelectOnly<?> select = (SelectOnly<?>)transformedQuery;
//            return select.cols;
//         }
//         else if (transformedQuery.isValidSubquery() && transformedQuery instanceof SelectFromWhere)
//         {
//            SelectFromWhere<?> sfw = (SelectFromWhere<?>)transformedQuery;
//            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");
//         }

      }
      else
         return super.virtualMethodCallValue(val, in);
   }

   protected JPQLQuery<?> handleInQueryStreamSource(
         TypedValue methodBase, TypedValue entity)
         throws TypedValueVisitorException
   {
      if (!(methodBase instanceof TypedValue.ArgValue))
         throw new TypedValueVisitorException("InQueryStreamSource comes from unknown source");
      int index = ((TypedValue.ArgValue)methodBase).getIndex();
      if (!argHandler.checkIsInQueryStreamSource(index))
         throw new TypedValueVisitorException("InQueryStreamSource comes from unknown source");
      if (!(entity instanceof ConstantValue.ClassConstant))
         throw new TypedValueVisitorException("Streaming an unknown type");
      Type type = ((ConstantValue.ClassConstant)entity).val;
      String entityName = config.metamodel.entityNameFromClassName(type.getClassName());
      if (entityName == null)
         throw new TypedValueVisitorException("Streaming an unknown type");
      return JPQLQuery.findAllEntities(entityName);
   }
  
   /**
    * if unknownVal is not a handled navigational link, null will be
    * returned. Otherwise, a query representing the link will be returned
    */
   protected JPQLQuery<?> handlePossibleNavigationalLink(TypedValue unknownVal, boolean expectingPluralLink, SymbExPassDown in) throws TypedValueVisitorException
   {
      // Figure out if it's an 1:N or N:M navigational link
      if (unknownVal instanceof MethodCallValue.VirtualMethodCallValue)
      {
         MethodCallValue.VirtualMethodCallValue val = (MethodCallValue.VirtualMethodCallValue)unknownVal;
         MethodSignature sig = val.getSignature();
         if ((expectingPluralLink && config.metamodel.isPluralAttributeLinkMethod(sig))
               || (!expectingPluralLink && config.metamodel.isSingularAttributeFieldMethod(sig) && config.metamodel.isFieldMethodAssociationType(sig)))
         {
            String linkName = expectingPluralLink ?
                  config.metamodel.nLinkMethodToLinkName(sig) : config.metamodel.fieldMethodToFieldName(sig);
            SymbExToColumns translator = config.newSymbExToColumns(argHandler);
           
            SymbExPassDown passdown = SymbExPassDown.with(val, false);
            ColumnExpressions<?> nLinkBase = val.base.visit(translator, passdown);
            // Traverse the chain, it should be a FromAlias at its base with
            // possible field accesses around it
            if (nLinkBase.isSingleColumn())
            {
               Expression expr = nLinkBase.getOnlyColumn();
               if (!(expr instanceof FromAliasExpression
                     || expr instanceof ReadFieldExpression))
                  return null;
            }
           
            // Create the query
            SelectFromWhere<?> query = new SelectFromWhere<>();
            From from = From.forNavigationalLinks(
                  new ReadFieldExpression(nLinkBase.getOnlyColumn(), linkName));
            query.cols = ColumnExpressions.singleColumn(
                  new SimpleRowReader<>(), new FromAliasExpression(from));
            query.froms.add(from);
            return query;
         }
      }
      return null;
   }
  
   @Override public JPQLQuery<?> staticMethodCallValue(MethodCallValue.StaticMethodCallValue val, SymbExPassDown in) throws TypedValueVisitorException
   {
      MethodSignature sig = val.getSignature();
      if (sig.equals(TransformationClassAnalyzer.streamFrom))
      {
         JPQLQuery<?> nLink = handlePossibleNavigationalLink(val.args.get(0), true, in);
         if (nLink != null) return nLink;
      }
      else if (sig.equals(TransformationClassAnalyzer.streamOf))
      {
         JPQLQuery<?> nLink = handlePossibleNavigationalLink(val.args.get(0), false, in);
         if (nLink != null) return nLink;
      }
      return super.staticMethodCallValue(val, in);
   }


}
TOP

Related Classes of org.jinq.jpa.transform.SymbExToSubQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.