com.frank.search.solr.repository.query.SolrQueryCreator.java Source code

Java tutorial

Introduction

Here is the source code for com.frank.search.solr.repository.query.SolrQueryCreator.java

Source

/*
 * Copyright 2012 - 2014 the original author or authors.
 *
 * 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.frank.search.solr.repository.query;

import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort;
import org.springframework.data.geo.Box;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.data.repository.query.parser.PartTree;
import com.frank.search.solr.core.mapping.SolrPersistentProperty;
import com.frank.search.solr.core.query.Criteria;
import com.frank.search.solr.core.query.Query;
import com.frank.search.solr.core.query.SimpleQuery;

import java.util.Collection;
import java.util.Iterator;

/**
 * Solr specific implmentation of an {@link org.springframework.data.repository.query.parser.AbstractQueryCreator} that constructs {@link Query}
 * 
 * @author Christoph Strobl
 * @author John Dorman
 */
class SolrQueryCreator extends AbstractQueryCreator<Query, Query> {

    private final MappingContext<?, SolrPersistentProperty> context;

    public SolrQueryCreator(PartTree tree, SolrParameterAccessor parameters,
            MappingContext<?, SolrPersistentProperty> context) {
        super(tree, parameters);
        this.context = context;
    }

    @Override
    protected Query create(Part part, Iterator<Object> iterator) {
        PersistentPropertyPath<SolrPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
        return new SimpleQuery(from(part.getType(),
                new Criteria(path.toDotPath(SolrPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
                iterator));
    }

    @Override
    protected Query and(Part part, Query base, Iterator<Object> iterator) {
        if (base == null) {
            return create(part, iterator);
        }
        PersistentPropertyPath<SolrPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
        return base.addCriteria(from(part.getType(),
                new Criteria(path.toDotPath(SolrPersistentProperty.PropertyToFieldNameConverter.INSTANCE)),
                iterator));
    }

    @Override
    protected Query or(Query base, Query query) {
        Criteria part = query.getCriteria();
        part.setPartIsOr(true);
        if (part.hasSiblings()) {
            boolean first = true;
            for (Criteria nested : part.getSiblings()) {
                if (first) {
                    nested.setPartIsOr(true);
                    first = false;
                }
                base.addCriteria(nested);
            }
        } else {
            base.addCriteria(part);
        }
        return base;
    }

    @Override
    protected Query complete(Query query, Sort sort) {
        if (query == null) {
            return null;
        }
        return query.addSort(sort);
    }

    private Criteria from(Type type, Criteria instance, Iterator<?> parameters) {
        Criteria criteria = instance;
        if (criteria == null) {
            criteria = new Criteria();
        }

        switch (type) {
        case TRUE:
            return criteria.is(true);
        case FALSE:
            return criteria.is(false);
        case SIMPLE_PROPERTY:
            return criteria.is(appendBoostAndGetParameterValue(criteria, parameters));
        case NEGATING_SIMPLE_PROPERTY:
            return criteria.is(appendBoostAndGetParameterValue(criteria, parameters)).not();
        case IS_NULL:
            return criteria.isNull();
        case IS_NOT_NULL:
            return criteria.isNotNull();
        case REGEX:
            return criteria.expression(appendBoostAndGetParameterValue(criteria, parameters).toString());
        case LIKE:
        case STARTING_WITH:
            return criteria.startsWith(asStringArray(appendBoostAndGetParameterValue(criteria, parameters)));
        case NOT_LIKE:
            return criteria.startsWith(asStringArray(appendBoostAndGetParameterValue(criteria, parameters))).not();
        case ENDING_WITH:
            return criteria.endsWith(asStringArray(appendBoostAndGetParameterValue(criteria, parameters)));
        case CONTAINING:
            return criteria.contains(asStringArray(appendBoostAndGetParameterValue(criteria, parameters)));
        case AFTER:
        case GREATER_THAN:
            return criteria.greaterThan(appendBoostAndGetParameterValue(criteria, parameters));
        case GREATER_THAN_EQUAL:
            return criteria.greaterThanEqual(appendBoostAndGetParameterValue(criteria, parameters));
        case BEFORE:
        case LESS_THAN:
            return criteria.lessThan(appendBoostAndGetParameterValue(criteria, parameters));
        case LESS_THAN_EQUAL:
            return criteria.lessThanEqual(appendBoostAndGetParameterValue(criteria, parameters));
        case BETWEEN:
            return criteria.between(appendBoostAndGetParameterValue(criteria, parameters),
                    appendBoostAndGetParameterValue(criteria, parameters));
        case IN:
            return criteria.in(asArray(appendBoostAndGetParameterValue(criteria, parameters)));
        case NOT_IN:
            return criteria.in(asArray(appendBoostAndGetParameterValue(criteria, parameters))).not();
        case NEAR:
            return createNearCriteria(parameters, criteria);
        case WITHIN:
            return criteria.within((Point) getBindableValue((BindableSolrParameter) parameters.next()),
                    (Distance) getBindableValue((BindableSolrParameter) parameters.next()));
        default:
            throw new InvalidDataAccessApiUsageException("Illegal criteria found '" + type + "'.");
        }
    }

    private Object appendBoostAndGetParameterValue(Criteria criteria, Iterator<?> iterator) {
        Object param = iterator.next();
        if (param instanceof BindableSolrParameter) {
            BindableSolrParameter bindable = (BindableSolrParameter) param;
            appendBoost(criteria, bindable);
            return bindable.getValue();
        }
        return param;
    }

    private Criteria appendBoost(Criteria criteria, BindableSolrParameter parameter) {
        if (!Float.isNaN(parameter.getBoost())) {
            criteria.boost(parameter.getBoost());
        }
        return criteria;
    }

    private Object getBindableValue(BindableSolrParameter parameter) {
        if (parameter == null) {
            return null;
        }
        return parameter.getValue();
    }

    private Criteria createNearCriteria(Iterator<?> parameters, Criteria criteria) {
        Object value = getBindableValue((BindableSolrParameter) parameters.next());
        if (value instanceof Box) {
            return criteria.near((Box) value);
        } else {
            return criteria.near((Point) value,
                    (Distance) getBindableValue((BindableSolrParameter) parameters.next()));
        }
    }

    private Object[] asArray(Object o) {
        if (o instanceof Collection) {
            return ((Collection<?>) o).toArray();
        } else if (o.getClass().isArray()) {
            return (Object[]) o;
        }
        return new Object[] { o };
    }

    @SuppressWarnings("unchecked")
    private String[] asStringArray(Object o) {
        if (o instanceof Collection) {
            Collection<?> col = (Collection<?>) o;
            if (col.isEmpty()) {
                return new String[0];
            } else {
                if (!(col.iterator().next() instanceof String)) {
                    throw new IllegalArgumentException("Parameter has to be a collection of String.");
                }
                return ((Collection<String>) o).toArray(new String[col.size()]);
            }
        } else if (o.getClass().isArray()) {
            if (!(o instanceof String[])) {
                throw new IllegalArgumentException("Parameter has to be an array of String.");
            }
            return (String[]) o;
        }
        return new String[] { o.toString() };
    }

}