All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.yawp.repository.query.QueryBuilder Maven / Gradle / Ivy

There is a newer version: 2.08alpha
Show newest version
package io.yawp.repository.query;

import io.yawp.repository.IdRef;
import io.yawp.repository.ObjectModel;
import io.yawp.repository.Repository;
import io.yawp.repository.query.condition.BaseCondition;
import io.yawp.repository.query.condition.Condition;
import io.yawp.repository.query.condition.SimpleCondition;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class QueryBuilder {

	private Class clazz;

	private ObjectModel model;

	private Repository r;

	private IdRef parentId;

	private BaseCondition condition;

	private List preOrders = new ArrayList();

	private List postOrders = new ArrayList();

	private Integer limit;

	private String cursor;

	public static  QueryBuilder q(Class clazz, Repository r) {
		return new QueryBuilder(clazz, r);
	}

	private QueryBuilder(Class clazz, Repository r) {
		this.clazz = clazz;
		this.r = r;
		this.model = new ObjectModel(clazz);
	}

	public  QueryTransformer transform(String transformName) {
		return new QueryTransformer(this, transformName);
	}

	public QueryBuilder and(String field, String operator, Object value) {
		return where(field, operator, value);
	}

	public QueryBuilder where(String field, String operator, Object value) {
		return where(Condition.c(field, operator, value));
	}

	public QueryBuilder where(BaseCondition c) {
		if (condition == null) {
			condition = c;
		} else {
			condition = Condition.and(condition, c);
		}

		condition.init(r, clazz);
		return this;
	}

	public QueryBuilder and(BaseCondition c) {
		return where(c);
	}

	public QueryBuilder from(IdRef parentId) {
		if (parentId == null) {
			this.parentId = null;
			return this;
		}

		this.parentId = parentId;
		return this;
	}

	public QueryBuilder order(String property) {
		order(property, null);
		return this;
	}

	public QueryBuilder order(String property, String direction) {
		preOrders.add(new QueryOrder(null, property, direction));
		return this;
	}

	public QueryBuilder sort(String property) {
		sort(property, null);
		return this;
	}

	public QueryBuilder sort(String property, String direction) {
		sort(null, property, direction);
		return this;
	}

	public QueryBuilder sort(String entity, String property, String direction) {
		postOrders.add(new QueryOrder(entity, property, direction));
		return this;
	}

	public QueryBuilder limit(int limit) {
		this.limit = limit;
		return this;
	}

	public QueryBuilder cursor(String cursor) {
		this.cursor = cursor;
		return this;
	}

	public IdRef getParentId() {
		return parentId;
	}

	public String getCursor() {
		return this.cursor;
	}

	public void setCursor(String cursor) {
		this.cursor = cursor;
	}

	public QueryBuilder options(QueryOptions options) {
		if (options.getCondition() != null) {
			where(options.getCondition());
		}

		if (options.getPreOrders() != null) {
			preOrders.addAll(options.getPreOrders());
		}

		if (options.getPostOrders() != null) {
			postOrders.addAll(options.getPostOrders());
		}

		if (options.getLimit() != null) {
			limit(options.getLimit());
		}

		return this;
	}

	public Integer getLimit() {
		return limit;
	}

	public List getPreOrders() {
		return preOrders;
	}

	public BaseCondition getCondition() {
		return condition;
	}

	public Repository getRepository() {
		return this.r;
	}

	public ObjectModel getModel() {
		return model;
	}

	public List executeQueryList() {
		r.namespace().set(getClazz());
		try {
			return executeQuery();
		} finally {
			r.namespace().reset();
		}
	}

	public List list() {
		List list = executeQueryList();
		sortList(list);
		return list;
	}

	public T first() {
		r.namespace().set(getClazz());
		try {
			if (isQueryById()) {
				return executeQueryById();
			}
			return executeQueryFirst();
		} finally {
			r.namespace().reset();
		}
	}

	private T executeQueryFirst() {
		limit(1);

		List list = executeQuery();
		if (list.size() == 0) {
			return null;
		}
		return list.get(0);
	}

	public T only() throws NoResultException, MoreThanOneResultException {
		r.namespace().set(getClazz());
		try {
			T object = null;

			if (isQueryById()) {
				object = executeQueryById();
			} else {
				object = executeQueryOnly();
			}

			if (object == null) {
				throw new NoResultException();
			}

			return object;
		} finally {
			r.namespace().reset();
		}
	}

	private T executeQueryOnly() throws MoreThanOneResultException {
		List list = executeQuery();
		if (list.size() == 0) {
			return null;
		}
		if (list.size() == 1) {
			return list.get(0);
		}
		throw new MoreThanOneResultException();
	}

	private List executeQuery() {
		List objects = r.driver().query().objects(this);
		return postFilter(objects);
	}

	private List postFilter(List objects) {
		if (condition == null || !condition.hasPostFilter()) {
			return objects;
		}

		return condition.applyPostFilter(objects);
	}

	@SuppressWarnings("unchecked")
	private T executeQueryById() {
		SimpleCondition c = (SimpleCondition) condition;
		IdRef id = (IdRef) c.getWhereValue();

		return r.driver().query().fetch(id);
	}

	private boolean isQueryById() {
		if (condition == null || !(condition instanceof SimpleCondition)) {
			return false;
		}

		SimpleCondition c = (SimpleCondition) condition;
		return c.isIdField() && c.isEqualOperator();
	}

	public void sortList(List objects) {
		if (postOrders.size() == 0) {
			return;
		}

		Collections.sort(objects, new Comparator() {
			@Override
			public int compare(Object o1, Object o2) {
				for (QueryOrder order : postOrders) {
					int compare = order.compare(o1, o2);

					if (compare == 0) {
						continue;
					}

					return compare;
				}
				return 0;
			}
		});
	}

	protected Class getClazz() {
		return clazz;
	}

	public QueryBuilder whereById(String operator, IdRef id) {
		return from(id.getParentId()).where(model.getIdField().getName(), operator, id);
	}

	public T fetch(IdRef idRef) {
		return whereById("=", idRef).only();
	}

	public T fetch(Long id) {
		IdRef idRef = IdRef.create(r, clazz, id);
		return fetch(idRef);
	}

	public T fetch(String name) {
		IdRef idRef = IdRef.create(r, clazz, name);
		return fetch(idRef);
	}

	public List> ids() {
		r.namespace().set(getClazz());
		try {
			List> ids = r.driver().query().ids(this);
			return ids;
		} finally {
			r.namespace().reset();
		}
	}

	public IdRef onlyId() throws NoResultException, MoreThanOneResultException {

		List> ids = ids();

		if (ids.size() == 0) {
			throw new NoResultException();
		}

		if (ids.size() > 1) {
			throw new MoreThanOneResultException();
		}

		return ids.get(0);
	}

}