package org.molgenis.data.support;
import org.molgenis.data.*;
import org.molgenis.data.QueryRule.Operator;
import java.util.*;
import java.util.stream.Stream;
public class QueryImpl<E extends Entity> implements Query<E>
{
private final List<List<QueryRule>> rules = new ArrayList<>();
private int offset;
private int pageSize;
private Sort sort;
/**
* {@link Fetch} that defines which entity attributes to retrieve.
*/
private Fetch fetch;
@Override
public Repository<E> getRepository()
{
return repository;
}
public void setRepository(Repository<E> repository)
{
this.repository = repository;
}
private Repository<E> repository;
public static Query<Entity> query()
{
return new QueryImpl<>();
}
public static Query<Entity> EQ(String attributeName, Object value)
{
return query().eq(attributeName, value);
}
public static Query<Entity> IN(String attributeName, Iterable<?> values)
{
return query().in(attributeName, values);
}
public QueryImpl()
{
this.rules.add(new ArrayList<>());
}
public QueryImpl(Repository<E> repository)
{
this();
this.repository = repository;
}
public QueryImpl(Query<E> q)
{
this();
for (QueryRule rule : q.getRules())
{
addRule(rule);
}
this.pageSize = q.getPageSize();
this.offset = q.getOffset();
this.sort = q.getSort();
this.fetch = q.getFetch();
}
public QueryImpl(QueryRule queryRule)
{
this();
addRule(queryRule);
}
public QueryImpl(List<QueryRule> queryRules)
{
this();
queryRules.forEach(this::addRule);
}
public void addRule(QueryRule rule)
{
this.rules.get(this.rules.size() - 1).add(rule);
}
@Override
public Long count()
{
if (repository == null) throw new RuntimeException("Query failed: repository not set");
return repository.count(this);
}
@Override
public Stream<E> findAll()
{
if (repository == null) throw new RuntimeException("Query failed: repository not set");
return repository.findAll(this);
}
@Override
public E findOne()
{
if (repository == null) throw new RuntimeException("Query failed: repository not set");
return repository.findOne(this);
}
@Override
public List<QueryRule> getRules()
{
if (this.rules.size() > 1)
throw new MolgenisDataException("Nested query not closed, use unnest() or unnestAll()");
if (this.rules.size() > 0)
{
List<QueryRule> rules = this.rules.get(this.rules.size() - 1);
return Collections.unmodifiableList(rules);
}
else return Collections.emptyList();
}
@Override
public int getPageSize()
{
return pageSize;
}
public QueryImpl<E> setPageSize(int pageSize)
{
this.pageSize = pageSize;
return this;
}
@Override
public int getOffset()
{
return offset;
}
public QueryImpl<E> setOffset(int offset)
{
this.offset = offset;
return this;
}
@Override
public Sort getSort()
{
return sort;
}
public void setSort(Sort sort)
{
this.sort = sort;
}
@Override
public Query<E> search(String searchTerms)
{
rules.get(this.rules.size() - 1).add(new QueryRule(Operator.SEARCH, searchTerms));
return this;
}
@Override
public Query<E> search(String field, String searchTerms)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.SEARCH, searchTerms));
return this;
}
@Override
public Query<E> or()
{
rules.get(this.rules.size() - 1).add(new QueryRule(Operator.OR));
return this;
}
@Override
public Query<E> and()
{
rules.get(this.rules.size() - 1).add(new QueryRule(Operator.AND));
return this;
}
@Override
public Query<E> not()
{
rules.get(this.rules.size() - 1).add(new QueryRule(Operator.NOT));
return this;
}
@Override
public Query<E> like(String field, String value)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.LIKE, value));
return this;
}
@Override
public Query<E> eq(String field, Object value)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.EQUALS, value));
return this;
}
@Override
public Query<E> in(String field, Iterable<?> valueIterable)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.IN, valueIterable));
return this;
}
@Override
public Query<E> gt(String field, Object value)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.GREATER, value));
return this;
}
@Override
public Query<E> ge(String field, Object value)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.GREATER_EQUAL, value));
return this;
}
@Override
public Query<E> le(String field, Object value)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.LESS_EQUAL, value));
return this;
}
@Override
public Query<E> lt(String field, Object value)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.LESS, value));
return this;
}
@Override
public Query<E> nest()
{
// add element to our nesting list...
this.rules.add(new ArrayList<>());
return this;
}
@Override
public Query<E> unnest()
{
if (this.rules.size() == 1) throw new MolgenisDataException("Cannot unnest root element of query");
// remove last element and add to parent as nested rule
QueryRule nested = new QueryRule(Operator.NESTED, this.rules.get(this.rules.size() - 1));
this.rules.remove(this.rules.get(this.rules.size() - 1));
this.rules.get(this.rules.size() - 1).add(nested);
return this;
}
@Override
public Query<E> unnestAll()
{
while (this.rules.size() > 1)
{
unnest();
}
return this;
}
@Override
public Query<E> rng(String field, Object from, Object to)
{
rules.get(this.rules.size() - 1).add(new QueryRule(field, Operator.RANGE, Arrays.asList(from, to)));
return this;
}
@Override
public Query<E> pageSize(int pageSize)
{
setPageSize(pageSize);
return this;
}
@Override
public Query<E> offset(int offset)
{
setOffset(offset);
return this;
}
@Override
public Sort sort()
{
this.sort = new Sort();
return this.sort;
}
@Override
public Query<E> sort(Sort sort)
{
setSort(sort);
return this;
}
@Override
public Iterator<E> iterator()
{
if (repository == null) throw new RuntimeException("Query failed: repository not set");
return repository.findAll(this).iterator();
}
@Override
public Fetch getFetch()
{
return fetch;
}
@Override
public void setFetch(Fetch fetch)
{
this.fetch = fetch;
}
@Override
public Fetch fetch()
{
this.fetch = new Fetch();
return getFetch();
}
@Override
public Query<E> fetch(Fetch fetch)
{
setFetch(fetch);
return this;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + offset;
result = prime * result + pageSize;
result = prime * result + ((rules == null) ? 0 : rules.hashCode());
result = prime * result + ((sort == null) ? 0 : sort.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
@SuppressWarnings("unchecked") QueryImpl<Entity> other = (QueryImpl<Entity>) obj;
if (offset != other.offset) return false;
if (pageSize != other.pageSize) return false;
if (rules == null)
{
if (other.rules != null) return false;
}
else if (!rules.equals(other.rules)) return false;
if (sort == null)
{
if (other.sort != null) return false;
}
else if (!sort.equals(other.sort)) return false;
return true;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
if (rules.size() > 0)
{
if (rules.size() == 1)
{
List<QueryRule> rule = rules.get(0);
if (rule.size() > 0)
{
builder.append("rules=").append(rule);
}
}
else
{
builder.append("rules=").append(rules);
}
}
if (offset != 0)
{
if (builder.length() > 0)
{
builder.append(", ");
}
builder.append("offset=").append(offset);
}
if (pageSize != 0)
{
if (builder.length() > 0)
{
builder.append(", ");
}
builder.append("pageSize=").append(pageSize);
}
if (sort != null)
{
if (builder.length() > 0)
{
builder.append(", ");
}
builder.append("sort=").append(sort);
}
if (fetch != null)
{
if (builder.length() > 0)
{
builder.append(", ");
}
builder.append("fetch=").append(fetch);
}
return builder.toString();
}
}