Jackson serialization for facets

This commit is contained in:
Antonin Delpeuch 2018-09-28 08:54:50 +01:00
parent 761b748faa
commit 8f1c7cc2ab
11 changed files with 589 additions and 20 deletions

View File

@ -39,6 +39,8 @@ import java.util.Properties;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable; import com.google.refine.Jsonizable;
import com.google.refine.util.StringUtils; import com.google.refine.util.StringUtils;
@ -50,7 +52,9 @@ import com.google.refine.util.StringUtils;
* Facet choices that are presented to the user as text are stored as decorated values. * Facet choices that are presented to the user as text are stored as decorated values.
*/ */
public class DecoratedValue implements Jsonizable { public class DecoratedValue implements Jsonizable {
@JsonProperty("v")
final public Object value; final public Object value;
@JsonProperty("l")
final public String label; final public String label;
public DecoratedValue(Object value, String label) { public DecoratedValue(Object value, String label) {

View File

@ -2,6 +2,8 @@ package com.google.refine.browsing.facets;
import org.json.JSONObject; import org.json.JSONObject;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable; import com.google.refine.Jsonizable;
import com.google.refine.model.Project; import com.google.refine.model.Project;
@ -28,4 +30,10 @@ public interface FacetConfig extends Jsonizable {
* @return a computed facet on the given project. * @return a computed facet on the given project.
*/ */
public Facet apply(Project project); public Facet apply(Project project);
/**
* The facet type as stored in json.
*/
@JsonProperty("type")
public String getJsonType();
} }

View File

@ -36,12 +36,20 @@ package com.google.refine.browsing.facets;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.stream.Collectors;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.google.refine.ProjectManager; import com.google.refine.ProjectManager;
import com.google.refine.browsing.DecoratedValue; import com.google.refine.browsing.DecoratedValue;
import com.google.refine.browsing.FilteredRecords; import com.google.refine.browsing.FilteredRecords;
@ -60,24 +68,51 @@ import com.google.refine.model.Project;
import com.google.refine.util.JSONUtilities; import com.google.refine.util.JSONUtilities;
public class ListFacet implements Facet { public class ListFacet implements Facet {
public static final String ERR_TOO_MANY_CHOICES = "Too many choices";
/**
* Wrapper to respect the serialization format
*/
public static class DecoratedValueWrapper {
@JsonProperty("v")
public final DecoratedValue value;
@JsonCreator
public DecoratedValueWrapper(
@JsonProperty("v") DecoratedValue value) {
this.value = value;
}
}
/* /*
* Configuration * Configuration
*/ */
public static class ListFacetConfig implements FacetConfig { public static class ListFacetConfig implements FacetConfig {
@JsonProperty("name")
public String name; public String name;
@JsonProperty("expression")
public String expression; public String expression;
@JsonProperty("columnName")
public String columnName; public String columnName;
@JsonProperty("invert")
public boolean invert; public boolean invert;
// If true, then facet won't show the blank and error choices // If true, then facet won't show the blank and error choices
@JsonProperty("omitBlank")
public boolean omitBlank; public boolean omitBlank;
@JsonProperty("omitError")
public boolean omitError; public boolean omitError;
@JsonIgnore
public List<DecoratedValue> selection = new LinkedList<>(); public List<DecoratedValue> selection = new LinkedList<>();
@JsonProperty("selectNumber")
public boolean selectNumber; public boolean selectNumber;
@JsonProperty("selectDateTime")
public boolean selectDateTime; public boolean selectDateTime;
@JsonProperty("selectBoolean")
public boolean selectBoolean; public boolean selectBoolean;
@JsonProperty("selectBlank")
public boolean selectBlank; public boolean selectBlank;
@JsonProperty("selectError")
public boolean selectError; public boolean selectError;
@Override @Override
@ -107,6 +142,13 @@ public class ListFacet implements Facet {
writer.endObject(); writer.endObject();
} }
@JsonProperty("selection")
public List<DecoratedValueWrapper> getWrappedSelection() {
return selection.stream()
.map(e -> new DecoratedValueWrapper(e))
.collect(Collectors.toList());
}
@Override @Override
public void initializeFromJSON(JSONObject o) { public void initializeFromJSON(JSONObject o) {
name = o.getString("name"); name = o.getString("name");
@ -143,6 +185,27 @@ public class ListFacet implements Facet {
facet.initializeFromConfig(this, project); facet.initializeFromConfig(this, project);
return facet; return facet;
} }
@Override
public String getJsonType() {
return "list";
}
}
/**
* Wrapper class for choice counts and selection status for blank and error
*/
public static class OtherChoice {
@JsonProperty("s")
boolean selected;
@JsonProperty("c")
int count;
public OtherChoice(
@JsonProperty("s") boolean selected,
@JsonProperty("c") int count) {
this.selected = selected;
this.count = count;
}
} }
ListFacetConfig _config = new ListFacetConfig(); ListFacetConfig _config = new ListFacetConfig();
@ -167,6 +230,69 @@ public class ListFacet implements Facet {
public ListFacet() { public ListFacet() {
} }
@JsonProperty("name")
public String getName() {
return _config.name;
}
@JsonProperty("columnName")
public String getColumnName() {
return _config.columnName;
}
@JsonProperty("expression")
public String getExpression() {
return _config.expression;
}
@JsonProperty("invert")
public boolean getInvert() {
return _config.invert;
}
@JsonProperty("error")
@JsonInclude(Include.NON_NULL)
public String getError() {
if (_errorMessage == null && _choices.size() > getLimit()) {
return ERR_TOO_MANY_CHOICES;
}
return _errorMessage;
}
@JsonProperty("choiceCount")
@JsonInclude(Include.NON_NULL)
public Integer getChoiceCount() {
if (_errorMessage == null && _choices.size() > getLimit())
return _choices.size();
return null;
}
@JsonProperty("choices")
@JsonInclude(Include.NON_NULL)
public List<NominalFacetChoice> getChoices() {
if (getError() == null)
return _choices;
return null;
}
@JsonProperty("blankChoice")
@JsonInclude(Include.NON_NULL)
public OtherChoice getBlankChoice() {
if (getError() == null && !_config.omitBlank && (_config.selectBlank || _blankCount > 0)) {
return new OtherChoice(_config.selectBlank, _blankCount);
}
return null;
}
@JsonProperty("errorChoice")
@JsonInclude(Include.NON_NULL)
public OtherChoice getErrorChoice() {
if (getError() == null && !_config.omitError && (_config.selectError || _errorCount > 0)) {
return new OtherChoice(_config.selectError, _errorCount);
}
return null;
}
@Override @Override
public void write(JSONWriter writer, Properties options) public void write(JSONWriter writer, Properties options)
throws JSONException { throws JSONException {
@ -180,7 +306,7 @@ public class ListFacet implements Facet {
if (_errorMessage != null) { if (_errorMessage != null) {
writer.key("error"); writer.value(_errorMessage); writer.key("error"); writer.value(_errorMessage);
} else if (_choices.size() > getLimit()) { } else if (_choices.size() > getLimit()) {
writer.key("error"); writer.value("Too many choices"); writer.key("error"); writer.value(ERR_TOO_MANY_CHOICES);
writer.key("choiceCount"); writer.value(_choices.size()); writer.key("choiceCount"); writer.value(_choices.size());
} else { } else {
writer.key("choices"); writer.array(); writer.key("choices"); writer.array();

View File

@ -38,6 +38,8 @@ import java.util.Properties;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable; import com.google.refine.Jsonizable;
import com.google.refine.browsing.DecoratedValue; import com.google.refine.browsing.DecoratedValue;
@ -46,8 +48,11 @@ import com.google.refine.browsing.DecoratedValue;
* and a flag of whether it has been selected. * and a flag of whether it has been selected.
*/ */
public class NominalFacetChoice implements Jsonizable { public class NominalFacetChoice implements Jsonizable {
@JsonProperty("v")
final public DecoratedValue decoratedValue; final public DecoratedValue decoratedValue;
@JsonProperty("c")
public int count; public int count;
@JsonProperty("s")
public boolean selected; public boolean selected;
public NominalFacetChoice(DecoratedValue decoratedValue) { public NominalFacetChoice(DecoratedValue decoratedValue) {

View File

@ -39,6 +39,11 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.browsing.FilteredRecords; import com.google.refine.browsing.FilteredRecords;
import com.google.refine.browsing.FilteredRows; import com.google.refine.browsing.FilteredRows;
import com.google.refine.browsing.RecordFilter; import com.google.refine.browsing.RecordFilter;
@ -59,22 +64,35 @@ import com.google.refine.model.Project;
import com.google.refine.util.JSONUtilities; import com.google.refine.util.JSONUtilities;
public class RangeFacet implements Facet { public class RangeFacet implements Facet {
public static final String ERR_NO_NUMERIC_VALUE_PRESENT = "No numeric value present.";
/* /*
* Configuration, from the client side * Configuration, from the client side
*/ */
public static class RangeFacetConfig implements FacetConfig { public static class RangeFacetConfig implements FacetConfig {
@JsonProperty("name")
protected String _name; // name of facet protected String _name; // name of facet
@JsonProperty("expression")
protected String _expression; // expression to compute numeric value(s) per row protected String _expression; // expression to compute numeric value(s) per row
@JsonProperty("columnName")
protected String _columnName; // column to base expression on, if any protected String _columnName; // column to base expression on, if any
@JsonProperty(FROM)
protected double _from; // the numeric selection protected double _from; // the numeric selection
@JsonProperty(TO)
protected double _to; protected double _to;
@JsonProperty("selectNumeric")
protected boolean _selectNumeric; // whether the numeric selection applies, default true protected boolean _selectNumeric; // whether the numeric selection applies, default true
@JsonProperty("selectNonNumeric")
protected boolean _selectNonNumeric; protected boolean _selectNonNumeric;
@JsonProperty("selectBlank")
protected boolean _selectBlank; protected boolean _selectBlank;
@JsonProperty("selectError")
protected boolean _selectError; protected boolean _selectError;
@JsonIgnore
protected boolean _selected; // false if we're certain that all rows will match protected boolean _selected; // false if we're certain that all rows will match
// and there isn't any filtering to do // and there isn't any filtering to do
@ -122,6 +140,11 @@ public class RangeFacet implements Facet {
facet.initializeFromConfig(this, project); facet.initializeFromConfig(this, project);
return facet; return facet;
} }
@Override
public String getJsonType() {
return "range";
}
} }
RangeFacetConfig _config = new RangeFacetConfig(); RangeFacetConfig _config = new RangeFacetConfig();
@ -141,14 +164,22 @@ public class RangeFacet implements Facet {
protected int[] _baseBins; protected int[] _baseBins;
protected int[] _bins; protected int[] _bins;
@JsonProperty("baseNumericCount")
protected int _baseNumericCount; protected int _baseNumericCount;
@JsonProperty("baseNonNumericCount")
protected int _baseNonNumericCount; protected int _baseNonNumericCount;
@JsonProperty("baseBlankCount")
protected int _baseBlankCount; protected int _baseBlankCount;
@JsonProperty("baseErrorCount")
protected int _baseErrorCount; protected int _baseErrorCount;
@JsonProperty("numericCount")
protected int _numericCount; protected int _numericCount;
@JsonProperty("nonNumericCount")
protected int _nonNumericCount; protected int _nonNumericCount;
@JsonProperty("blankCount")
protected int _blankCount; protected int _blankCount;
@JsonProperty("errorCount")
protected int _errorCount; protected int _errorCount;
public RangeFacet() { public RangeFacet() {
@ -159,6 +190,100 @@ public class RangeFacet implements Facet {
protected static final String TO = "to"; protected static final String TO = "to";
protected static final String FROM = "from"; protected static final String FROM = "from";
@JsonProperty("name")
public String getName() {
return _config._name;
}
@JsonProperty("expression")
public String getExpression() {
return _config._expression;
}
@JsonProperty("columnName")
public String getColumnName() {
return _config._columnName;
}
@JsonProperty("error")
@JsonInclude(Include.NON_NULL)
public String getError() {
if (_errorMessage != null) {
return _errorMessage;
} else if (!isFiniteRange()) {
return ERR_NO_NUMERIC_VALUE_PRESENT;
}
return null;
}
@JsonIgnore
public boolean isFiniteRange() {
return !Double.isInfinite(_min) && !Double.isInfinite(_max);
}
@JsonProperty(MIN)
@JsonInclude(Include.NON_NULL)
public Double getMin() {
if (getError() == null) {
return _min;
}
return null;
}
@JsonProperty(MAX)
@JsonInclude(Include.NON_NULL)
public Double getMax() {
if (getError() == null) {
return _max;
}
return null;
}
@JsonProperty("step")
@JsonInclude(Include.NON_NULL)
public Double getStep() {
if (getError() == null) {
return _step;
}
return null;
}
@JsonProperty("bins")
@JsonInclude(Include.NON_NULL)
public int[] getBins() {
if (getError() == null) {
return _bins;
}
return null;
}
@JsonProperty("baseBins")
@JsonInclude(Include.NON_NULL)
public int[] getBaseBins() {
if (getError() == null) {
return _baseBins;
}
return null;
}
@JsonProperty(FROM)
@JsonInclude(Include.NON_NULL)
public Double getFrom() {
if (getError() == null) {
return _config._from;
}
return null;
}
@JsonProperty(TO)
@JsonInclude(Include.NON_NULL)
public Double getTo() {
if (getError() == null) {
return _config._to;
}
return null;
}
@Override @Override
public void write(JSONWriter writer, Properties options) public void write(JSONWriter writer, Properties options)
throws JSONException { throws JSONException {
@ -191,7 +316,7 @@ public class RangeFacet implements Facet {
writer.key(FROM); writer.value(_config._from); writer.key(FROM); writer.value(_config._from);
writer.key(TO); writer.value(_config._to); writer.key(TO); writer.value(_config._to);
} else { } else {
writer.key("error"); writer.value("No numeric value present."); writer.key("error"); writer.value(ERR_NO_NUMERIC_VALUE_PRESENT);
} }
writer.key("baseNumericCount"); writer.value(_baseNumericCount); writer.key("baseNumericCount"); writer.value(_baseNumericCount);

View File

@ -51,6 +51,11 @@ import org.json.JSONWriter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.browsing.FilteredRecords; import com.google.refine.browsing.FilteredRecords;
import com.google.refine.browsing.FilteredRows; import com.google.refine.browsing.FilteredRows;
import com.google.refine.browsing.RecordFilter; import com.google.refine.browsing.RecordFilter;
@ -80,33 +85,61 @@ public class ScatterplotFacet implements Facet {
* Configuration, from the client side * Configuration, from the client side
*/ */
public static class ScatterplotFacetConfig implements FacetConfig { public static class ScatterplotFacetConfig implements FacetConfig {
@JsonProperty("name")
protected String name; // name of facet protected String name; // name of facet
@JsonProperty(X_EXPRESSION)
protected String expression_x; // expression to compute the x numeric value(s) per row protected String expression_x; // expression to compute the x numeric value(s) per row
@JsonProperty(Y_EXPRESSION)
protected String expression_y; // expression to compute the y numeric value(s) per row protected String expression_y; // expression to compute the y numeric value(s) per row
@JsonProperty(X_COLUMN_NAME)
protected String columnName_x; // column to base the x expression on, if any protected String columnName_x; // column to base the x expression on, if any
@JsonProperty(Y_COLUMN_NAME)
protected String columnName_y; // column to base the y expression on, if any protected String columnName_y; // column to base the y expression on, if any
@JsonProperty(SIZE)
protected int size; protected int size;
@JsonIgnore
protected int dim_x; protected int dim_x;
@JsonIgnore
protected int dim_y; protected int dim_y;
@JsonIgnore
protected String rotation_str; protected String rotation_str;
@JsonIgnore
protected int rotation; protected int rotation;
@JsonIgnore
protected double l; protected double l;
@JsonProperty(DOT)
protected double dot; protected double dot;
@JsonIgnore
protected String color_str; protected String color_str;
@JsonIgnore
protected Color color; protected Color color;
@JsonProperty(FROM_X)
protected double from_x; // the numeric selection for the x axis, from 0 to 1 protected double from_x; // the numeric selection for the x axis, from 0 to 1
@JsonProperty(TO_X)
protected double to_x; protected double to_x;
@JsonProperty(FROM_Y)
protected double from_y; // the numeric selection for the y axis, from 0 to 1 protected double from_y; // the numeric selection for the y axis, from 0 to 1
@JsonProperty(TO_Y)
protected double to_y; protected double to_y;
protected boolean selected; // false if we're certain that all rows will match protected boolean selected; // false if we're certain that all rows will match
// and there isn't any filtering to do // and there isn't any filtering to do
@JsonProperty(DIM_X)
public String getDimX() {
return dim_x == LIN ? "lin" : "log";
}
@JsonProperty(DIM_Y)
public String getDimY() {
return dim_y == LIN ? "lin" : "log";
}
@Override @Override
public void write(JSONWriter writer, Properties options) public void write(JSONWriter writer, Properties options)
throws JSONException { throws JSONException {
@ -193,6 +226,11 @@ public class ScatterplotFacet implements Facet {
return NO_ROTATION; return NO_ROTATION;
} }
} }
@Override
public String getJsonType() {
return "scatterplot";
}
} }
ScatterplotFacetConfig config; ScatterplotFacetConfig config;
@ -255,6 +293,118 @@ public class ScatterplotFacet implements Facet {
} }
} }
@JsonProperty(NAME)
public String getName() {
return config.name;
}
@JsonProperty(X_COLUMN_NAME)
public String getXColumnName() {
return config.columnName_x;
}
@JsonProperty(X_EXPRESSION)
public String getXExpression() {
return config.expression_x;
}
@JsonProperty(Y_COLUMN_NAME)
public String getYColumnName() {
return config.columnName_y;
}
@JsonProperty(Y_EXPRESSION)
public String getYExpression() {
return config.expression_y;
}
@JsonProperty(SIZE)
public int getSize() {
return config.size;
}
@JsonProperty(DIM_X)
public int getDimX() {
return config.dim_x;
}
@JsonProperty(DIM_Y)
public int getDimY() {
return config.dim_y;
}
@JsonProperty(DOT)
public double getDot() {
return config.dot;
}
@JsonProperty(ROTATION)
public double getRotation() {
return config.rotation;
}
@JsonProperty(COLOR)
public String getColorString() {
return config.color_str;
}
@JsonProperty(IMAGE)
@JsonInclude(Include.NON_NULL)
public String getImage() {
if(IMAGE_URI) {
return image;
}
return null;
}
@JsonProperty(ERROR_X)
@JsonInclude(Include.NON_NULL)
public String getErrorX() {
return errorMessage_x;
}
@JsonProperty(FROM_X)
@JsonInclude(Include.NON_NULL)
public Double getFromX() {
if (errorMessage_x == null && !Double.isInfinite(min_x) && !Double.isInfinite(max_x)) {
return config.from_x;
}
return null;
}
@JsonProperty(TO_X)
@JsonInclude(Include.NON_NULL)
public Double getToX() {
if (errorMessage_x == null && !Double.isInfinite(min_x) && !Double.isInfinite(max_x)) {
return config.to_x;
}
return null;
}
@JsonProperty(ERROR_Y)
@JsonInclude(Include.NON_NULL)
public String getErrorY() {
return errorMessage_y;
}
@JsonProperty(FROM_Y)
@JsonInclude(Include.NON_NULL)
public Double getFromY() {
if (errorMessage_y == null && !Double.isInfinite(min_y) && !Double.isInfinite(max_y)) {
return config.from_y;
}
return null;
}
@JsonProperty(TO_Y)
@JsonInclude(Include.NON_NULL)
public Double getToY() {
if (errorMessage_y == null && !Double.isInfinite(min_y) && !Double.isInfinite(max_y)) {
return config.to_y;
}
return null;
}
@Override @Override
public void write(JSONWriter writer, Properties options) throws JSONException { public void write(JSONWriter writer, Properties options) throws JSONException {

View File

@ -40,6 +40,8 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.browsing.FilteredRecords; import com.google.refine.browsing.FilteredRecords;
import com.google.refine.browsing.FilteredRows; import com.google.refine.browsing.FilteredRows;
import com.google.refine.browsing.RecordFilter; import com.google.refine.browsing.RecordFilter;
@ -58,11 +60,17 @@ public class TextSearchFacet implements Facet {
* Configuration * Configuration
*/ */
public static class TextSearchFacetConfig implements FacetConfig { public static class TextSearchFacetConfig implements FacetConfig {
@JsonProperty("name")
protected String _name; protected String _name;
@JsonProperty("columnName")
protected String _columnName; protected String _columnName;
@JsonProperty("query")
protected String _query = null; protected String _query = null;
@JsonProperty("mode")
protected String _mode; protected String _mode;
@JsonProperty("caseSensitive")
protected boolean _caseSensitive; protected boolean _caseSensitive;
@JsonProperty("invert")
protected boolean _invert; protected boolean _invert;
@Override @Override
@ -97,6 +105,11 @@ public class TextSearchFacet implements Facet {
} }
_invert = o.has("invert") && o.getBoolean("invert"); _invert = o.has("invert") && o.getBoolean("invert");
} }
@Override
public String getJsonType() {
return "text";
}
} }
TextSearchFacetConfig _config = new TextSearchFacetConfig(); TextSearchFacetConfig _config = new TextSearchFacetConfig();
@ -110,6 +123,36 @@ public class TextSearchFacet implements Facet {
public TextSearchFacet() { public TextSearchFacet() {
} }
@JsonProperty("name")
public String getName() {
return _config._name;
}
@JsonProperty("columnName")
public String getColumnName() {
return _config._columnName;
}
@JsonProperty("query")
public String getQuery() {
return _config._query;
}
@JsonProperty("mode")
public String getMode() {
return _config._mode;
}
@JsonProperty("caseSensitive")
public boolean isCaseSensitive() {
return _config._caseSensitive;
}
@JsonProperty("invert")
public boolean isInverted() {
return _config._invert;
}
@Override @Override
public void write(JSONWriter writer, Properties options) public void write(JSONWriter writer, Properties options)
throws JSONException { throws JSONException {

View File

@ -39,6 +39,11 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.browsing.FilteredRecords; import com.google.refine.browsing.FilteredRecords;
import com.google.refine.browsing.FilteredRows; import com.google.refine.browsing.FilteredRows;
import com.google.refine.browsing.RecordFilter; import com.google.refine.browsing.RecordFilter;
@ -63,18 +68,28 @@ public class TimeRangeFacet implements Facet {
* Configuration, from the client side * Configuration, from the client side
*/ */
public static class TimeRangeFacetConfig implements FacetConfig { public static class TimeRangeFacetConfig implements FacetConfig {
@JsonProperty("name")
protected String _name; // name of facet protected String _name; // name of facet
@JsonProperty("expression")
protected String _expression; // expression to compute numeric value(s) per row protected String _expression; // expression to compute numeric value(s) per row
@JsonProperty("columnName")
protected String _columnName; // column to base expression on, if any protected String _columnName; // column to base expression on, if any
@JsonProperty(FROM)
protected double _from; // the numeric selection protected double _from; // the numeric selection
@JsonProperty(TO)
protected double _to; protected double _to;
@JsonProperty("selectTime")
protected boolean _selectTime; // whether the time selection applies, default true protected boolean _selectTime; // whether the time selection applies, default true
@JsonProperty("selectNonTime")
protected boolean _selectNonTime; protected boolean _selectNonTime;
@JsonProperty("selectBlank")
protected boolean _selectBlank; protected boolean _selectBlank;
@JsonProperty("selectError")
protected boolean _selectError; protected boolean _selectError;
@JsonIgnore
protected boolean _selected; // false if we're certain that all rows will match protected boolean _selected; // false if we're certain that all rows will match
// and there isn't any filtering to do // and there isn't any filtering to do
@ -123,6 +138,11 @@ public class TimeRangeFacet implements Facet {
facet.initializeFromConfig(this, project); facet.initializeFromConfig(this, project);
return facet; return facet;
} }
@Override
public String getJsonType() {
return "timerange";
}
} }
protected TimeRangeFacetConfig _config; protected TimeRangeFacetConfig _config;
@ -142,14 +162,22 @@ public class TimeRangeFacet implements Facet {
/* /*
* Computed data * Computed data
*/ */
@JsonProperty("baseTimeCount")
protected int _baseTimeCount; protected int _baseTimeCount;
@JsonProperty("baseNonTimeCount")
protected int _baseNonTimeCount; protected int _baseNonTimeCount;
@JsonProperty("baseBlankCount")
protected int _baseBlankCount; protected int _baseBlankCount;
@JsonProperty("baseErrorCount")
protected int _baseErrorCount; protected int _baseErrorCount;
@JsonProperty("timeCount")
protected int _timeCount; protected int _timeCount;
@JsonProperty("nonTimeCount")
protected int _nonTimeCount; protected int _nonTimeCount;
@JsonProperty("blankCount")
protected int _blankCount; protected int _blankCount;
@JsonProperty("errorCount")
protected int _errorCount; protected int _errorCount;
protected static final String MIN = "min"; protected static final String MIN = "min";
@ -157,6 +185,87 @@ public class TimeRangeFacet implements Facet {
protected static final String TO = "to"; protected static final String TO = "to";
protected static final String FROM = "from"; protected static final String FROM = "from";
@JsonProperty("name")
public String getName() {
return _config._name;
}
@JsonProperty("expression")
public String getExpression() {
return _config._expression;
}
@JsonProperty("columnName")
public String getColumnName() {
return _config._columnName;
}
@JsonProperty("error")
@JsonInclude(Include.NON_NULL)
public String getError() {
return _errorMessage;
}
@JsonProperty(MIN)
@JsonInclude(Include.NON_NULL)
public Double getMin() {
if(getError() == null) {
return _min;
}
return null;
}
@JsonProperty(MAX)
@JsonInclude(Include.NON_NULL)
public Double getMax() {
if(getError() == null) {
return _max;
}
return null;
}
@JsonProperty("step")
@JsonInclude(Include.NON_NULL)
public Double getStep() {
return _step;
}
@JsonProperty("bins")
@JsonInclude(Include.NON_NULL)
public int[] getBins() {
if (getError() == null) {
return _bins;
}
return null;
}
@JsonProperty("baseBins")
@JsonInclude(Include.NON_NULL)
public int[] getBaseBins() {
if (getError() == null) {
return _baseBins;
}
return null;
}
@JsonProperty(FROM)
@JsonInclude(Include.NON_NULL)
public Double getFrom() {
if (getError() == null) {
return _config._from;
}
return null;
}
@JsonProperty(TO)
@JsonInclude(Include.NON_NULL)
public Double getTo() {
if (getError() == null) {
return _config._to;
}
return null;
}
@Override @Override
public void write(JSONWriter writer, Properties options) throws JSONException { public void write(JSONWriter writer, Properties options) throws JSONException {
@ -169,9 +278,9 @@ public class TimeRangeFacet implements Facet {
writer.key("error"); writer.value(_errorMessage); writer.key("error"); writer.value(_errorMessage);
} else { } else {
if (!Double.isInfinite(_min) && !Double.isInfinite(_max)) { if (!Double.isInfinite(_min) && !Double.isInfinite(_max)) {
writer.key(MIN); writer.value(_min); writer.key(MIN); writer.value((long)_min);
writer.key(MAX); writer.value(_max); writer.key(MAX); writer.value((long)_max);
writer.key("step"); writer.value(_step); writer.key("step"); writer.value((long)_step);
writer.key("bins"); writer.array(); writer.key("bins"); writer.array();
for (int b : _bins) { for (int b : _bins) {
@ -185,8 +294,8 @@ public class TimeRangeFacet implements Facet {
} }
writer.endArray(); writer.endArray();
writer.key(FROM); writer.value(_config._from); writer.key(FROM); writer.value((long)_config._from);
writer.key(TO); writer.value(_config._to); writer.key(TO); writer.value((long)_config._to);
} }
writer.key("baseTimeCount"); writer.value(_baseTimeCount); writer.key("baseTimeCount"); writer.value(_baseTimeCount);

View File

@ -66,8 +66,8 @@ public class SerializationFilters {
@Override @Override
public void serialize(Double arg0, JsonGenerator gen, SerializerProvider s) public void serialize(Double arg0, JsonGenerator gen, SerializerProvider s)
throws IOException { throws IOException {
if (new Double(arg0.intValue()).equals(arg0)) { if (new Double(arg0.longValue()).equals(arg0)) {
gen.writeNumber(arg0.intValue()); gen.writeNumber(arg0.longValue());
} else { } else {
gen.writeNumber(arg0); gen.writeNumber(arg0);
} }

View File

@ -20,13 +20,13 @@ public class TimeRangeFacetTests extends RefineTest {
+ "\"name\":\"my column\"," + "\"name\":\"my column\","
+ "\"expression\":\"value\"," + "\"expression\":\"value\","
+ "\"columnName\":\"my column\"," + "\"columnName\":\"my column\","
+ "\"min\":1.199329445E12," + "\"min\":1199329445000,"
+ "\"max\":1.51496695E12," + "\"max\":1514966950000,"
+ "\"step\":3.1556952E10," + "\"step\":31556952000,"
+ "\"bins\":[1,0,0,0,1,0,0,0,0,0,1]," + "\"bins\":[1,0,0,0,1,0,0,0,0,0,1],"
+ "\"baseBins\":[1,0,0,0,1,0,0,0,0,0,1]," + "\"baseBins\":[1,0,0,0,1,0,0,0,0,0,1],"
+ "\"from\":1.262443349E12," + "\"from\":1262443349000,"
+ "\"to\":1.51496695E12," + "\"to\":1514966950000,"
+ "\"baseTimeCount\":3," + "\"baseTimeCount\":3,"
+ "\"baseNonTimeCount\":1," + "\"baseNonTimeCount\":1,"
+ "\"baseBlankCount\":0," + "\"baseBlankCount\":0,"

View File

@ -21,7 +21,6 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.google.refine.Jsonizable; import com.google.refine.Jsonizable;
import com.google.refine.util.JSONUtilities; import com.google.refine.util.JSONUtilities;
import com.google.refine.util.JsonViews;
import com.google.refine.util.ParsingUtilities; import com.google.refine.util.ParsingUtilities;