package org.ektorp; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import org.ektorp.util.Assert; /** * * @author henrik lundgren * */ public class ViewResult implements Iterable<ViewResult.Row>, Serializable { private static final String OFFSET_FIELD_NAME = "offset"; private static final String TOTAL_ROWS_FIELD_NAME = "total_rows"; private static final String UPDATE_SEQ = "update_seq"; private static final long serialVersionUID = 4750290767933801714L; private int totalRows = -1; private int offset = -1; private String updateSeq; @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="SE_BAD_FIELD") private List<Row> rows; public ViewResult(JsonNode resultNode, boolean ignoreNotFound) { Assert.notNull(resultNode, "resultNode may not be null"); Assert.isTrue(resultNode.findPath("rows").isArray(), "result must contain 'rows' field of array type"); if (resultNode.get(TOTAL_ROWS_FIELD_NAME) != null) { totalRows = resultNode.get(TOTAL_ROWS_FIELD_NAME).intValue(); } if (resultNode.get(OFFSET_FIELD_NAME) != null) { offset = resultNode.get(OFFSET_FIELD_NAME).intValue(); } if (resultNode.get(UPDATE_SEQ) != null) { updateSeq = resultNode.get(UPDATE_SEQ).textValue(); if(updateSeq == null) { updateSeq = Long.toString(resultNode.get(UPDATE_SEQ).intValue()); } } JsonNode rowsNode = resultNode.get("rows"); rows = new ArrayList<ViewResult.Row>(rowsNode.size()); for (JsonNode n : rowsNode) { if (!(ignoreNotFound && n.has(Row.ERROR_FIELD_NAME))) { rows.add(new Row(n)); } } } public List<Row> getRows() { return rows; } public int getSize() { return rows.size(); } /** * * @return -1 if result did not contain an offset field */ public int getOffset() { return offset; } @JsonProperty void setOffset(int offset) { this.offset = offset; } /** * * @return -1 if result did not contain a total_rows field */ public int getTotalRows() { return totalRows; } @JsonProperty(TOTAL_ROWS_FIELD_NAME) void setTotalRows(int i) { this.totalRows = i; } /** * @return -1L if result did not contain an update_seq field */ public long getUpdateSeq() { if(updateSeq != null) { return Long.parseLong(updateSeq); } return -1L; } /** * @return false if db is an Cloudant instance. */ public boolean isUpdateSeqNumeric() { return updateSeq != null && updateSeq.matches("^\\d*$"); } /** * * @return null if result did not contain an update_seq field */ public String getUpdateSeqAsString() { return updateSeq; } @JsonProperty(UPDATE_SEQ) public void setUpdateSeq(String updateSeq) { this.updateSeq = updateSeq; } public Iterator<ViewResult.Row> iterator() { return rows.iterator(); } public boolean isEmpty() { return rows.isEmpty(); } @Override public String toString() { StringBuilder builder = new StringBuilder("{\n\"total_rows\":"); builder.append(totalRows); builder.append(",\n\"offset\":"); builder.append(offset); builder.append(",\n\"rows\":"); builder.append(rows.toString()); builder.append("\n}"); return builder.toString(); } public static class Row { static final String VALUE_FIELD_NAME = "value"; static final String ID_FIELD_NAME = "id"; static final String KEY_FIELD_NAME = "key"; static final String DOC_FIELD_NAME = "doc"; static final String ERROR_FIELD_NAME = "error"; private final JsonNode rowNode; @JsonCreator public Row(JsonNode rowNode) { Assert.notNull(rowNode, "row node may not be null"); this.rowNode = rowNode; if (getError() != null) { throw new ViewResultException(getKeyAsNode(), getError()); } } public String getId() { return nodeAsString(getIdAsNode()); } public JsonNode getIdAsNode() { return rowNode.findPath(ID_FIELD_NAME); } public String getKey() { return nodeAsString(getKeyAsNode()); } public JsonNode getKeyAsNode() { return rowNode.findPath(KEY_FIELD_NAME); } public String getValue() { return nodeAsString(getValueAsNode()); } public int getValueAsInt() { return getValueAsNode().asInt(0); } public JsonNode getValueAsNode() { return rowNode.findPath(VALUE_FIELD_NAME); } public String getDoc() { return nodeAsString(rowNode.findValue(DOC_FIELD_NAME)); } public JsonNode getDocAsNode() { return rowNode.findPath(DOC_FIELD_NAME); } private String getError() { return nodeAsString(rowNode.get(ERROR_FIELD_NAME)); } private String nodeAsString(JsonNode node) { if (isNull(node)) return null; return node.isContainerNode() ? node.toString() : node.asText(); } private boolean isNull(JsonNode node) { return node == null || node.isNull() || node.isMissingNode(); } @Override public String toString() { return rowNode.toString(); } } }