org.springframework.data.document.mongodb.query.Criteria.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.data.document.mongodb.query.Criteria.java

Source

/*
 * Copyright 2010-2011 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 org.springframework.data.document.mongodb.query;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.springframework.data.document.InvalidDocumentStoreApiUsageException;
import org.springframework.data.document.mongodb.geo.Box;
import org.springframework.data.document.mongodb.geo.Circle;
import org.springframework.data.document.mongodb.geo.Point;
import org.springframework.util.Assert;

public class Criteria implements CriteriaDefinition {

    /**
     * Custom "not-null" object as we have to be able to work with {@literal null} values as well.
     */
    private static final Object NOT_SET = new Object();

    private String key;

    private List<Criteria> criteriaChain;

    private LinkedHashMap<String, Object> criteria = new LinkedHashMap<String, Object>();

    private Object isValue = NOT_SET;

    public Criteria(String key) {
        this.criteriaChain = new ArrayList<Criteria>();
        this.criteriaChain.add(this);
        this.key = key;
    }

    protected Criteria(List<Criteria> criteriaChain, String key) {
        this.criteriaChain = criteriaChain;
        this.criteriaChain.add(this);
        this.key = key;
    }

    /**
     * Static factory method to create a Criteria using the provided key
     * 
     * @param key
     * @return
     */
    public static Criteria where(String key) {
        return new Criteria(key);
    }

    public static Criteria whereId() {
        return new Criteria("id");
    }

    /**
     * Static factory method to create a Criteria using the provided key
     * 
     * @param key
     * @return
     */
    public Criteria and(String key) {
        return new Criteria(this.criteriaChain, key);
    }

    /**
     * Creates a criterion using equality
     * 
     * @param o
     * @return
     */
    public Criteria is(Object o) {
        if (isValue != NOT_SET) {
            throw new InvalidDocumentStoreApiUsageException(
                    "Multiple 'is' values declared. You need to use 'and' with multiple criteria");
        }
        if (this.criteria.size() > 0 && "$not".equals(this.criteria.keySet().toArray()[this.criteria.size() - 1])) {
            throw new InvalidDocumentStoreApiUsageException(
                    "Invalid query: 'not' can't be used with 'is' - use 'ne' instead.");
        }
        this.isValue = o;
        return this;
    }

    /**
     * Creates a criterion using the $ne operator
     * 
     * @param o
     * @return
     */
    public Criteria ne(Object o) {
        criteria.put("$ne", o);
        return this;
    }

    /**
     * Creates a criterion using the $lt operator
     * 
     * @param o
     * @return
     */
    public Criteria lt(Object o) {
        criteria.put("$lt", o);
        return this;
    }

    /**
     * Creates a criterion using the $lte operator
     * 
     * @param o
     * @return
     */
    public Criteria lte(Object o) {
        criteria.put("$lte", o);
        return this;
    }

    /**
     * Creates a criterion using the $gt operator
     * 
     * @param o
     * @return
     */
    public Criteria gt(Object o) {
        criteria.put("$gt", o);
        return this;
    }

    /**
     * Creates a criterion using the $gte operator
     * 
     * @param o
     * @return
     */
    public Criteria gte(Object o) {
        criteria.put("$gte", o);
        return this;
    }

    /**
     * Creates a criterion using the $in operator
     * 
     * @param o the values to match against 
     * @return
     */
    public Criteria in(Object... o) {
        if (o.length > 1 && o[1] instanceof Collection) {
            throw new InvalidDocumentStoreApiUsageException(
                    "You can only pass in one argument of type " + o[1].getClass().getName());
        }
        criteria.put("$in", o);
        return this;
    }

    /**
     * Creates a criterion using the $in operator
     * 
     * @param c the collection containing the values to match against 
     * @return
     */
    public Criteria in(Collection<?> c) {
        System.out.println(c.getClass());
        criteria.put("$in", c.toArray());
        return this;
    }

    /**
     * Creates a criterion using the $nin operator
     * 
     * @param o
     * @return
     */
    public Criteria nin(Object... o) {
        criteria.put("$nin", o);
        return this;
    }

    /**
     * Creates a criterion using the $mod operator
     * 
     * @param value
     * @param remainder
     * @return
     */
    public Criteria mod(Number value, Number remainder) {
        List<Object> l = new ArrayList<Object>();
        l.add(value);
        l.add(remainder);
        criteria.put("$mod", l);
        return this;
    }

    /**
     * Creates a criterion using the $all operator
     * 
     * @param o
     * @return
     */
    public Criteria all(Object... o) {
        criteria.put("$all", o);
        return this;
    }

    /**
     * Creates a criterion using the $size operator
     * 
     * @param s
     * @return
     */
    public Criteria size(int s) {
        criteria.put("$size", s);
        return this;
    }

    /**
     * Creates a criterion using the $exists operator
     * 
     * @param b
     * @return
     */
    public Criteria exists(boolean b) {
        criteria.put("$exists", b);
        return this;
    }

    /**
     * Creates a criterion using the $type operator
     * 
     * @param t
     * @return
     */
    public Criteria type(int t) {
        criteria.put("$type", t);
        return this;
    }

    /**
     * Creates a criterion using the $not meta operator which affects the clause directly following
     * 
     * @return
     */
    public Criteria not() {
        criteria.put("$not", null);
        return this;
    }

    /**
     * Creates a criterion using a $regex
     * 
     * @param re
     * @return
     */
    public Criteria regex(String re) {
        criteria.put("$regex", re);
        return this;
    }

    /**
     * Creates a geospatial criterion using a $within $center operation
     * 
     * @param circle
     *          must not be {@literal null}
     * @return
     */
    public Criteria withinCenter(Circle circle) {
        Assert.notNull(circle);
        LinkedList<Object> list = new LinkedList<Object>();
        list.addLast(circle.getCenter().asArray());
        list.add(circle.getRadius());
        criteria.put("$within", new BasicDBObject("$center", list));
        return this;
    }

    /**
     * Creates a geospatial criterion using a $within $center operation. This is only available for Mongo 1.7 and higher.
     * 
     * @param circle
     *          must not be {@literal null}
     * @return
     */
    public Criteria withinCenterSphere(Circle circle) {
        Assert.notNull(circle);
        LinkedList<Object> list = new LinkedList<Object>();
        list.addLast(circle.getCenter().asArray());
        list.add(circle.getRadius());
        criteria.put("$within", new BasicDBObject("$centerSphere", list));
        return this;
    }

    /**
     * Creates a geospatial criterion using a $within $box operation
     * 
     * @param box
     * @return
     */
    public Criteria withinBox(Box box) {
        Assert.notNull(box);
        LinkedList<double[]> list = new LinkedList<double[]>();
        list.addLast(box.getLowerLeft().asArray());
        list.addLast(box.getUpperRight().asArray());
        criteria.put("$within", new BasicDBObject("$box", list));
        return this;
    }

    /**
     * Creates a geospatial criterion using a $near operation
     * 
     * @param point
     *          must not be {@literal null}
     * @return
     */
    public Criteria near(Point point) {
        Assert.notNull(point);
        criteria.put("$near", point.asArray());
        return this;
    }

    /**
     * Creates a geospatial criterion using a $nearSphere operation. This is only available for Mongo 1.7 and higher.
     * 
     * @param point
     *          must not be {@literal null}
     * @return
     */
    public Criteria nearSphere(Point point) {
        Assert.notNull(point);
        criteria.put("$nearSphere", point.asArray());
        return this;
    }

    /**
     * Creates a geospatical criterion using a $maxDistance operation, for use with $near
     * 
     * @param maxDistance
     * @return
     */
    public Criteria maxDistance(double maxDistance) {
        criteria.put("$maxDistance", maxDistance);
        return this;
    }

    /**
     * Creates a criterion using the $elemMatch operator
     * 
     * @param c
     * @return
     */
    public Criteria elemMatch(Criteria c) {
        criteria.put("$elemMatch", c.getCriteriaObject());
        return this;
    }

    /**
     * Creates an or query using the $or operator for all of the provided queries
     * 
     * @param queries
     */
    public void or(List<Query> queries) {
        criteria.put("$or", queries);
    }

    public String getKey() {
        return this.key;
    }

    /*
        * (non-Javadoc)
        *
        * @see org.springframework.datastore.document.mongodb.query.Criteria#
        * getCriteriaObject(java.lang.String)
        */
    public DBObject getCriteriaObject() {
        if (this.criteriaChain.size() == 1) {
            return criteriaChain.get(0).getSingleCriteriaObject();
        } else {
            DBObject criteriaObject = new BasicDBObject();
            for (Criteria c : this.criteriaChain) {
                criteriaObject.putAll(c.getSingleCriteriaObject());
            }
            return criteriaObject;
        }
    }

    protected DBObject getSingleCriteriaObject() {
        DBObject dbo = new BasicDBObject();
        boolean not = false;
        for (String k : this.criteria.keySet()) {
            if (not) {
                DBObject notDbo = new BasicDBObject();
                notDbo.put(k, this.criteria.get(k));
                dbo.put("$not", notDbo);
                not = false;
            } else {
                if ("$not".equals(k)) {
                    not = true;
                } else {
                    dbo.put(k, this.criteria.get(k));
                }
            }
        }
        DBObject queryCriteria = new BasicDBObject();
        if (isValue != NOT_SET) {
            queryCriteria.put(this.key, this.isValue);
            queryCriteria.putAll(dbo);
        } else {
            queryCriteria.put(this.key, dbo);
        }
        return queryCriteria;
    }

}