package com.leanengine.server.entity;
import com.google.appengine.api.datastore.Cursor;
import com.leanengine.server.JsonUtils;
import com.leanengine.server.LeanException;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ObjectNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class LeanQuery {
private final String kind;
private List<QueryFilter> filters = new ArrayList<QueryFilter>();
private List<QuerySort> sorts = new ArrayList<QuerySort>();
private Cursor cursor;
private Integer offset;
private Integer limit;
public LeanQuery(String kind) {
this.kind = kind;
}
public void addFilter(String property, QueryFilter.FilterOperator operator, Object value) {
filters.add(new QueryFilter(property, operator, value));
}
public void addSort(String property, QuerySort.SortDirection direction) {
sorts.add(new QuerySort(property, direction));
}
public String getKind() {
return kind;
}
public Cursor getCursor() {
return cursor;
}
public void setCursor(Cursor cursor) {
this.cursor = cursor;
}
public List<QuerySort> getSorts() {
return sorts;
}
public List<QueryFilter> getFilters() {
return filters;
}
public JsonNode toJson() throws LeanException {
ObjectNode json = JsonUtils.getObjectMapper().createObjectNode();
json.put("kind", kind);
if (!filters.isEmpty()) {
ObjectNode jsonFilters = JsonUtils.getObjectMapper().createObjectNode();
for (QueryFilter filter : filters) {
ObjectNode jsonFilter;
if (jsonFilters.has(filter.getProperty())) {
jsonFilter = (ObjectNode) jsonFilters.get(filter.getProperty());
} else {
jsonFilter = JsonUtils.getObjectMapper().createObjectNode();
}
JsonUtils.addTypedNode(jsonFilter, filter.getOperator().toJSON(), filter.getValue());
jsonFilters.put(filter.getProperty(), jsonFilter);
}
json.put("filter", jsonFilters);
}
if (!sorts.isEmpty()) {
ObjectNode jsonSorts = JsonUtils.getObjectMapper().createObjectNode();
for (QuerySort sort : sorts) {
jsonSorts.put(sort.getProperty(), sort.getDirection().toJSON());
}
json.put("sort", jsonSorts);
}
if (this.cursor != null) {
json.put("cursor", cursor.toWebSafeString());
}
return json;
}
public static LeanQuery fromJson(String json) throws LeanException {
ObjectNode jsonNode;
try {
jsonNode = (ObjectNode) JsonUtils.getObjectMapper().readTree(json);
} catch (IOException e) {
throw new LeanException(LeanException.Error.QueryJSON);
} catch (ClassCastException cce) {
throw new LeanException(LeanException.Error.QueryJSON, " Expected JSON object, instead got JSON array.");
}
// get the 'kind' of the query
LeanQuery query = new LeanQuery(jsonNode.get("kind").getTextValue());
if (query.getKind() == null) {
throw new LeanException(LeanException.Error.QueryJSON, " Missing 'kind' property.");
}
// get 'filter'
ObjectNode filters;
try {
filters = (ObjectNode) jsonNode.get("filter");
} catch (ClassCastException cce) {
throw new LeanException(LeanException.Error.QueryJSON, " Property 'filter' must be a JSON object.");
}
if (filters != null) {
Iterator<String> filterIterator = filters.getFieldNames();
while (filterIterator.hasNext()) {
String filterProperty = filterIterator.next();
ObjectNode filter;
try {
filter = (ObjectNode) filters.get(filterProperty);
} catch (ClassCastException cce) {
throw new LeanException(LeanException.Error.QueryJSON, " Filter value must be a JSON object.");
}
Iterator<String> operatorIterator = filter.getFieldNames();
while (operatorIterator.hasNext()) {
String operator = operatorIterator.next();
Object filterValue = JsonUtils.propertyFromJson(filter.get(operator));
query.addFilter(
filterProperty,
QueryFilter.FilterOperator.create(operator),
filterValue);
}
}
}
// get 'sort'
ObjectNode sorts;
try {
sorts = (ObjectNode) jsonNode.get("sort");
} catch (ClassCastException cce) {
throw new LeanException(LeanException.Error.QueryJSON, " Property 'sort' must be a JSON object.");
}
if (sorts != null) {
Iterator<String> sortIterator = sorts.getFieldNames();
while (sortIterator.hasNext()) {
String sortProperty = sortIterator.next();
query.addSort(sortProperty, QuerySort.SortDirection.create(sorts.get(sortProperty).getTextValue()));
}
}
// get 'cursor'
JsonNode cursorNode = jsonNode.get("cursor");
if (cursorNode != null) {
query.cursor = Cursor.fromWebSafeString(cursorNode.getTextValue());
}
// get 'cursor'
JsonNode limitNode = jsonNode.get("limit");
if (limitNode != null) {
query.limit = limitNode.getIntValue();
}
// get 'cursor'
JsonNode offsetNode = jsonNode.get("offset");
if (offsetNode != null) {
query.offset = offsetNode.getIntValue();
}
return query;
}
public Integer getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public Integer getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
}