diff options
Diffstat (limited to 'src/main/java/com')
| -rw-r--r-- | src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java | 217 | 
1 files changed, 115 insertions, 102 deletions
| diff --git a/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java b/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java index ebcb60a..11df215 100644 --- a/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java +++ b/src/main/java/com/amazon/carbonado/qe/JoinedQueryExecutor.java @@ -42,186 +42,199 @@ import com.amazon.carbonado.info.ChainedProperty;  import com.amazon.carbonado.info.OrderedProperty;
  import com.amazon.carbonado.info.StorableInfo;
  import com.amazon.carbonado.info.StorableIntrospector;
 +import com.amazon.carbonado.info.StorableProperty;
  /**
 - * QueryExecutor which wraps an executor for type <i>A</i>, follows a join, and
 - * produces type <i>B</i>.
 + * QueryExecutor which wraps an executor for type <i>source</i>, follows a
 + * join, and produces type <i>target</i>.
   *
   * @author Brian S O'Neill
   * @see JoinedCursorFactory
 + * @param <S> source type
 + * @param <T> target type
   */
 -public class JoinedQueryExecutor<A extends Storable, B extends Storable>
 -    extends AbstractQueryExecutor<B>
 +public class JoinedQueryExecutor<S extends Storable, T extends Storable>
 +    extends AbstractQueryExecutor<T>
  {
 -    private static <A extends Storable, B extends Storable> OrderingList<B>
 -        transformOrdering(Class<B> bType,
 -                          String bToAProperty,
 -                          QueryExecutor<A> aExecutor)
 +    private static <S extends Storable, T extends Storable> OrderingList<T>
 +        transformOrdering(Class<T> targetType,
 +                          String targetToSourceProperty,
 +                          QueryExecutor<S> sourceExecutor)
      {
 -        StorableInfo<B> bInfo = StorableIntrospector.examine(bType);
 +        StorableInfo<T> targetInfo = StorableIntrospector.examine(targetType);
 -        OrderingList<A> aOrdering = aExecutor.getOrdering();
 -        int size = aOrdering.size();
 -        OrderedProperty<B>[] bOrdering = new OrderedProperty[size];
 +        OrderingList<S> sourceOrdering = sourceExecutor.getOrdering();
 +        int size = sourceOrdering.size();
 +        OrderedProperty<T>[] targetOrdering = new OrderedProperty[size];
          for (int i=0; i<size; i++) {
 -            OrderedProperty<A> aProp = aOrdering.get(i);
 -            String bName = bToAProperty + '.' + aProp.getChainedProperty();
 -            OrderedProperty<B> bProp = OrderedProperty
 -                .get(ChainedProperty.parse(bInfo, bName), aProp.getDirection());
 -            bOrdering[i] = bProp;
 +            OrderedProperty<S> sourceProp = sourceOrdering.get(i);
 +            String targetName = targetToSourceProperty + '.' + sourceProp.getChainedProperty();
 +            OrderedProperty<T> targetProp = OrderedProperty
 +                .get(ChainedProperty.parse(targetInfo, targetName), sourceProp.getDirection());
 +            targetOrdering[i] = targetProp;
          }
 -        return OrderingList.get(bOrdering);
 +        return OrderingList.get(targetOrdering);
      }
 -    private final JoinedCursorFactory<A, B> mFactory;
 -    private final QueryExecutor<A> mAExecutor;
 +    private final ChainedProperty<T> mTargetToSourceProperty;
 +    private final JoinedCursorFactory<S, T> mFactory;
 +    private final QueryExecutor<S> mSourceExecutor;
 -    private final FilterValues<A> mAFilterValues;
 -    private final Filter<B> mBFilter;
 -    private final OrderingList<B> mBOrdering;
 +    private final FilterValues<S> mSourceFilterValues;
 +    private final Filter<T> mTargetFilter;
 +    private final OrderingList<T> mTargetOrdering;
      /**
       * @param repo access to storage instances for properties
 -     * @param bType type of <i>B</i> instances
 -     * @param bToAProperty property of <i>B</i> type which maps to instances of
 -     * <i>A</i> type.
 -     * @param aExecutor executor for <i>A</i> instances
 -     * @throws IllegalArgumentException if property type is not <i>A</i>
 +     * @param targetType type of <i>target</i> instances
 +     * @param targetToSourceProperty property of <i>target</i> type which maps
 +     * to instances of <i>source</i> type.
 +     * @param sourceExecutor executor for <i>source</i> instances
 +     * @throws IllegalArgumentException if property type is not <i>source</i>
       */
      public JoinedQueryExecutor(Repository repo,
 -                               Class<B> bType,
 -                               String bToAProperty,
 -                               QueryExecutor<A> aExecutor)
 +                               Class<T> targetType,
 +                               String targetToSourceProperty,
 +                               QueryExecutor<S> sourceExecutor)
          throws SupportException, FetchException, RepositoryException
      {
 -        mFactory = new JoinedCursorFactory<A, B>
 -            (repo, bType, bToAProperty, aExecutor.getStorableType());
 -        mAExecutor = aExecutor;
 -
 -        Filter<A> aFilter = aExecutor.getFilter();
 -
 -        mAFilterValues = aFilter.initialFilterValues();
 -        mBFilter = aFilter.accept(new FilterTransformer(bType, bToAProperty), null);
 -
 -        mBOrdering = transformOrdering(bType, bToAProperty, aExecutor);
 +        this(repo,
 +             ChainedProperty.parse(StorableIntrospector.examine(targetType),
 +                                   targetToSourceProperty),
 +             sourceExecutor);
      }
      /**
       * @param repo access to storage instances for properties
 -     * @param bToAProperty property of <i>B</i> type which maps to instances of
 -     * <i>A</i> type.
 +     * @param targetToSourceProperty property of <i>target</i> type which maps
 +     * to instances of <i>source</i> type.
       * @param aExecutor executor for <i>A</i> instances
       * @throws IllegalArgumentException if property type is not <i>A</i>
       */
      public JoinedQueryExecutor(Repository repo,
 -                               ChainedProperty<B> bToAProperty,
 -                               QueryExecutor<A> aExecutor)
 +                               ChainedProperty<T> targetToSourceProperty,
 +                               QueryExecutor<S> sourceExecutor)
          throws SupportException, FetchException, RepositoryException
      {
 -        mFactory = new JoinedCursorFactory<A, B>
 -            (repo, bToAProperty, aExecutor.getStorableType());
 -        mAExecutor = aExecutor;
 +        mTargetToSourceProperty = targetToSourceProperty;
 +        mFactory = new JoinedCursorFactory<S, T>
 +            (repo, targetToSourceProperty, sourceExecutor.getStorableType());
 +        mSourceExecutor = sourceExecutor;
 -        Filter<A> aFilter = aExecutor.getFilter();
 +        Filter<S> sourceFilter = sourceExecutor.getFilter();
 -        mAFilterValues = aFilter.initialFilterValues();
 -        mBFilter = aFilter.accept(new FilterTransformer(bToAProperty), null);
 +        mSourceFilterValues = sourceFilter.initialFilterValues();
 +        mTargetFilter = sourceFilter.accept(new FilterTransformer(), null);
 -        mBOrdering = transformOrdering(bToAProperty.getPrimeProperty().getEnclosingType(),
 -                                       bToAProperty.toString(), aExecutor);
 +        mTargetOrdering = transformOrdering
 +            (targetToSourceProperty.getPrimeProperty().getEnclosingType(),
 +             targetToSourceProperty.toString(), sourceExecutor);
      }
 -    public Filter<B> getFilter() {
 -        return mBFilter;
 +    public Filter<T> getFilter() {
 +        return mTargetFilter;
      }
 -    public Cursor<B> fetch(FilterValues<B> values) throws FetchException {
 -        return mFactory.join(mAExecutor.fetch(transferValues(values)));
 +    public Cursor<T> fetch(FilterValues<T> values) throws FetchException {
 +        return mFactory.join(mSourceExecutor.fetch(transferValues(values)));
      }
 -    public OrderingList<B> getOrdering() {
 -        return mBOrdering;
 +    public OrderingList<T> getOrdering() {
 +        return mTargetOrdering;
      }
 -    public boolean printPlan(Appendable app, int indentLevel, FilterValues<B> values)
 +    public boolean printPlan(Appendable app, int indentLevel, FilterValues<T> values)
          throws IOException
      {
 -        indent(app, indentLevel);
 -        app.append("join: ");
 -        // FIXME: split multi-way join into more nested levels
 -        app.append(getStorableType().getName());
 -        newline(app);
 -        mAExecutor.printPlan(app, increaseIndent(indentLevel), transferValues(values));
 +        int chainCount = mTargetToSourceProperty.getChainCount();
 +
 +        for (int i = -1; i < chainCount; i++) {
 +            indent(app, indentLevel);
 +            app.append("join: ");
 +
 +            StorableProperty<?> prop;
 +            if (i == -1) {
 +                prop = mTargetToSourceProperty.getPrimeProperty();
 +            } else {
 +                prop = mTargetToSourceProperty.getChainedProperty(i);
 +            }
 +
 +            app.append(prop.getEnclosingType().getName());
 +            newline(app);
 +            indent(app, indentLevel);
 +            app.append("...via property: ");
 +            app.append(prop.getName());
 +            newline(app);
 +            indentLevel = increaseIndent(indentLevel);
 +        }
 +
 +        mSourceExecutor.printPlan(app, indentLevel, transferValues(values));
          return true;
      }
 -    private FilterValues<A> transferValues(FilterValues<B> values) {
 -        if (values == null || mAFilterValues == null) {
 +    private FilterValues<S> transferValues(FilterValues<T> values) {
 +        if (values == null || mSourceFilterValues == null) {
              return null;
          }
 -        return mAFilterValues.withValues(values.getSuppliedValues());
 +        return mSourceFilterValues.withValues(values.getSuppliedValues());
      }
 -    private class FilterTransformer extends Visitor<A, Filter<B>, Object> {
 -        private final Class<B> mBType;
 -        private final String mBToAProperty;
 -
 -        FilterTransformer(Class<B> bType, String bToAProperty) {
 -            mBType = bType;
 -            mBToAProperty = bToAProperty;
 -        }
 +    private class FilterTransformer extends Visitor<S, Filter<T>, Object> {
 +        private final Class<T> mTargetType;
 -        FilterTransformer(ChainedProperty<B> bToAProperty) {
 -            mBType = bToAProperty.getPrimeProperty().getEnclosingType();
 -            mBToAProperty = bToAProperty.toString();
 +        FilterTransformer() {
 +            mTargetType = mTargetToSourceProperty.getPrimeProperty().getEnclosingType();
          }
 -        public Filter<B> visit(OrFilter<A> aFilter, Object param) {
 -            return aFilter.getLeftFilter().accept(this, param)
 -                .and(aFilter.getRightFilter().accept(this, param));
 +        public Filter<T> visit(OrFilter<S> sourceFilter, Object param) {
 +            return sourceFilter.getLeftFilter().accept(this, param)
 +                .and(sourceFilter.getRightFilter().accept(this, param));
          }
 -        public Filter<B> visit(AndFilter<A> aFilter, Object param) {
 -            return aFilter.getLeftFilter().accept(this, param)
 -                .or(aFilter.getRightFilter().accept(this, param));
 +        public Filter<T> visit(AndFilter<S> sourceFilter, Object param) {
 +            return sourceFilter.getLeftFilter().accept(this, param)
 +                .or(sourceFilter.getRightFilter().accept(this, param));
          }
 -        public Filter<B> visit(PropertyFilter<A> aFilter, Object param) {
 +        public Filter<T> visit(PropertyFilter<S> sourceFilter, Object param) {
              String name;
 -            ChainedProperty<A> aChainedProp = aFilter.getChainedProperty();
 -            if (mBType == aChainedProp.getPrimeProperty().getEnclosingType()) {
 -                // If type if A is already B, (which violates generic type
 +            ChainedProperty<S> sourceChainedProp = sourceFilter.getChainedProperty();
 +            if (mTargetType == sourceChainedProp.getPrimeProperty().getEnclosingType()) {
 +                // If type of S is already T, (which violates generic type
                  // signature) then it came from join index analysis.
 -                name = aChainedProp.toString();
 +                name = sourceChainedProp.toString();
              } else {
 -                StringBuilder nameBuilder = new StringBuilder(mBToAProperty).append('.');
 +                StringBuilder nameBuilder = new StringBuilder();
                  try {
 -                    aChainedProp.appendTo(nameBuilder);
 +                    mTargetToSourceProperty.appendTo(nameBuilder);
 +                    nameBuilder.append('.');
 +                    sourceChainedProp.appendTo(nameBuilder);
                  } catch (IOException e) {
                      // Not gonna happen
                  }
                  name = nameBuilder.toString();
              }
 -            Filter<B> bFilter = Filter.getOpenFilter(mBType);
 -            if (aFilter.isConstant()) {
 -                bFilter = bFilter.and(name, aFilter.getOperator(), aFilter.constant());
 +            Filter<T> targetFilter = Filter.getOpenFilter(mTargetType);
 +            if (sourceFilter.isConstant()) {
 +                targetFilter = targetFilter
 +                    .and(name, sourceFilter.getOperator(), sourceFilter.constant());
              } else {
 -                bFilter = bFilter.and(name, aFilter.getOperator());
 +                targetFilter = targetFilter.and(name, sourceFilter.getOperator());
              }
 -            return bFilter;
 +            return targetFilter;
          }
 -        public Filter<B> visit(OpenFilter<A> aFilter, Object param) {
 -            return Filter.getOpenFilter(mBType);
 +        public Filter<T> visit(OpenFilter<S> sourceFilter, Object param) {
 +            return Filter.getOpenFilter(mTargetType);
          }
 -        public Filter<B> visit(ClosedFilter<A> aFilter, Object param) {
 -            return Filter.getClosedFilter(mBType);
 +        public Filter<T> visit(ClosedFilter<S> sourceFilter, Object param) {
 +            return Filter.getClosedFilter(mTargetType);
          }
      }
  }
 | 
