Package com.mysema.query.collections

Source Code of com.mysema.query.collections.DefaultQueryEngine

/*
* Copyright 2011, Mysema Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mysema.query.collections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.mysema.codegen.Evaluator;
import com.mysema.commons.lang.IteratorAdapter;
import com.mysema.query.JoinExpression;
import com.mysema.query.JoinType;
import com.mysema.query.QueryMetadata;
import com.mysema.query.QueryModifiers;
import com.mysema.query.types.ArrayConstructorExpression;
import com.mysema.query.types.Expression;
import com.mysema.query.types.Operation;
import com.mysema.query.types.Operator;
import com.mysema.query.types.Ops;
import com.mysema.query.types.Order;
import com.mysema.query.types.OrderSpecifier;

/**
* Default implementation of the {@link QueryEngine} interface
*
* @author tiwe
*
*/
@SuppressWarnings("unchecked")
public class DefaultQueryEngine implements QueryEngine {

    private static volatile QueryEngine DEFAULT;

    public static QueryEngine getDefault() {
        if (DEFAULT == null) {
            DEFAULT = new DefaultQueryEngine(new DefaultEvaluatorFactory(CollQueryTemplates.DEFAULT));
        }
        return DEFAULT;
    }

    private final DefaultEvaluatorFactory evaluatorFactory;

    public DefaultQueryEngine(DefaultEvaluatorFactory evaluatorFactory) {
        this.evaluatorFactory = evaluatorFactory;
    }

    @Override
    public long count(QueryMetadata metadata, Map<Expression<?>, Iterable<?>> iterables) {
        if (metadata.getJoins().size() == 1) {
            return evaluateSingleSource(metadata, iterables, true).size();
        } else {
            return evaluateMultipleSources(metadata, iterables, true).size();
        }
    }

    @Override
    public boolean exists(QueryMetadata metadata, Map<Expression<?>, Iterable<?>> iterables) {
        QueryModifiers modifiers = metadata.getModifiers();
        metadata.setLimit(1l);
        try {
            if (metadata.getJoins().size() == 1) {
                return !evaluateSingleSource(metadata, iterables, true).isEmpty();
            } else {
                return !evaluateMultipleSources(metadata, iterables, true).isEmpty();
            }
        } finally {
            metadata.setModifiers(modifiers);
        }
    }

    @Override
    public <T> List<T> list(QueryMetadata metadata, Map<Expression<?>, Iterable<?>> iterables,
            Expression<T> projection) {
        if (metadata.getJoins().size() == 1) {
            return evaluateSingleSource(metadata, iterables, false);
        } else {
            return evaluateMultipleSources(metadata, iterables, false);
        }
    }

    private <T> List<T> distinct(List<T> list) {
        List<T> rv = new ArrayList<T>(list.size());
        if (!list.isEmpty() && list.get(0) != null && list.get(0).getClass().isArray()) {
            Set set = new HashSet(list.size());
            for (T o : list) {
                if (set.add(ImmutableList.copyOf((Object[])o))) {
                    rv.add(o);
                }
            }
            return rv;
        } else {
            for (T o : list) {
                if (!rv.contains(o)) {
                    rv.add(o);
                }
            }
        }
        return rv;
    }

    private List evaluateMultipleSources(QueryMetadata metadata, Map<Expression<?>,
            Iterable<?>> iterables, boolean count) {
        // from where
        Evaluator<List<Object[]>> ev = evaluatorFactory.createEvaluator(metadata, metadata.getJoins(), metadata.getWhere());
        List<Iterable<?>> iterableList = new ArrayList<Iterable<?>>(metadata.getJoins().size());
        for (JoinExpression join : metadata.getJoins()) {
            if (join.getType() == JoinType.DEFAULT) {
                iterableList.add(iterables.get(join.getTarget()));
            }
        }
        List<?> list = ev.evaluate(iterableList.toArray());

        if (!count && !list.isEmpty()) {
            List<Expression<?>> sources = new ArrayList<Expression<?>>(metadata.getJoins().size());
            for (JoinExpression join : metadata.getJoins()) {
                if (join.getType() == JoinType.DEFAULT) {
                    sources.add(join.getTarget());
                } else {
                    Operation target = (Operation) join.getTarget();
                    sources.add(target.getArg(1));
                }
            }
            // ordered
            if (!metadata.getOrderBy().isEmpty()) {
                order(metadata, sources, list);
            }
            // projection
            list = project(metadata, sources, list);
            // limit + offset
            if (metadata.getModifiers().isRestricting()) {
                list = metadata.getModifiers().subList(list);
            }
            if (list.isEmpty()) {
                return list;
            }
        }

        // distinct
        if (metadata.isDistinct()) {
            list = distinct(list);
        }

        return list;
    }

    private List evaluateSingleSource(QueryMetadata metadata, Map<Expression<?>,
            Iterable<?>> iterables, boolean count) {
        final Expression<?> source = metadata.getJoins().get(0).getTarget();
        final List<Expression<?>> sources = Collections.<Expression<?>>singletonList(source);
        final Iterable<?> iterable = iterables.values().iterator().next();
        List<?> list;
        if (iterable instanceof List) {
            list = (List)iterable;
        } else {
            list = IteratorAdapter.asList(iterable.iterator());
        }

        // from & where
        if (metadata.getWhere() != null) {
            Evaluator<List<?>> evaluator = (Evaluator)evaluatorFactory
                    .createEvaluator(metadata, source, metadata.getWhere());
            list = evaluator.evaluate(list);
        }

        if (!count && !list.isEmpty()) {
            // ordered
            if (!metadata.getOrderBy().isEmpty()) {
                // clone list
                if (list == iterable) {
                    list = new ArrayList(list);
                }
                order(metadata, sources, list);
            }
            // projection
            if (metadata.getProjection().size() > 1 || !metadata.getProjection().get(0).equals(source)) {
                list = project(metadata, sources, list);
            }
            // limit + offset
            if (metadata.getModifiers().isRestricting()) {
                list = metadata.getModifiers().subList(list);
            }
            if (list.isEmpty()) {
                return list;
            }
        }

        // distinct
        if (metadata.isDistinct()) {
            list = distinct(list);
        }

        return list;

    }

    private void order(QueryMetadata metadata, List<Expression<?>> sources, List<?> list) {
        // create a projection for the order
        List<OrderSpecifier<?>> orderBy = metadata.getOrderBy();
        Expression<Object>[] orderByExpr = new Expression[orderBy.size()];
        boolean[] directions = new boolean[orderBy.size()];
        for (int i = 0; i < orderBy.size(); i++) {
            orderByExpr[i] = (Expression) orderBy.get(i).getTarget();
            directions[i] = orderBy.get(i).getOrder() == Order.ASC;
        }
        Expression<?> expr = new ArrayConstructorExpression<Object>(Object[].class, orderByExpr);
        Evaluator orderEvaluator = evaluatorFactory.create(metadata, sources, expr);
        Collections.sort(list, new MultiComparator(orderEvaluator, directions));
    }

    private List<?> project(QueryMetadata metadata, List<Expression<?>> sources, List<?> list) {
        Expression<?> projection = metadata.getProjection().get(0);
        Operator<?> aggregator = null;
        if (projection instanceof Operation && Ops.aggOps.contains(((Operation)projection).getOperator())) {
            Operation<?> aggregation = (Operation<?>)projection;
            aggregator = aggregation.getOperator();
            projection = aggregation.getArg(0);
        }
        Evaluator projectionEvaluator = evaluatorFactory.create(metadata, sources, projection);
        EvaluatorFunction transformer = new EvaluatorFunction(projectionEvaluator);
        List target = new ArrayList();
        Iterators.addAll(target, Iterators.transform(list.iterator(), transformer));
        if (aggregator != null) {
            return ImmutableList.of(CollQueryFunctions.aggregate(target, projection, aggregator));
        } else {
            return target;
        }
    }



}
TOP

Related Classes of com.mysema.query.collections.DefaultQueryEngine

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.