Refactor schema expressions

This commit is contained in:
Antonin Delpeuch 2018-01-24 17:21:13 +00:00
parent a476b2bf0a
commit b99b72b071
24 changed files with 195 additions and 249 deletions

View File

@ -17,7 +17,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
public class WbDateConstant extends WbDateExpr {
public class WbDateConstant implements WbValueExpr<TimeValue> {
public static Map<SimpleDateFormat,Integer> acceptedFormats = ImmutableMap.<SimpleDateFormat,Integer>builder()
.put(new SimpleDateFormat("yyyy"), 9)

View File

@ -1,11 +0,0 @@
package org.openrefine.wikidata.schema;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.TimeValue;
public abstract class WbDateExpr extends WbValueExpr {
@Override
public abstract TimeValue evaluate(ExpressionContext ctxt)
throws SkipSchemaExpressionException;
}

View File

@ -5,38 +5,19 @@ import java.text.ParseException;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.TimeValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.model.Cell;
public class WbDateVariable extends WbDateExpr {
private String columnName;
@JsonCreator
public WbDateVariable(
@JsonProperty("columnName") String columnName) {
this.columnName = columnName;
}
public class WbDateVariable extends WbVariableExpr<TimeValue> {
@Override
public TimeValue evaluate(ExpressionContext ctxt)
public TimeValue fromCell(Cell cell, ExpressionContext ctxt)
throws SkipSchemaExpressionException {
Cell cell = ctxt.getCellByName(columnName);
if (cell != null) {
try {
// TODO accept parsed dates (without converting them to strings)
return WbDateConstant.parse(cell.value.toString());
} catch (ParseException e) {
}
try {
// TODO accept parsed dates (without converting them to strings)
return WbDateConstant.parse(cell.value.toString());
} catch (ParseException e) {
throw new SkipSchemaExpressionException();
}
throw new SkipSchemaExpressionException();
}
@JsonProperty("columnName")
public String getColumnName() {
return columnName;
}
}

View File

@ -1,17 +1,16 @@
package org.openrefine.wikidata.schema;
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
import org.openrefine.wikidata.schema.entityvalues.SuggestedItemIdValue;
import org.wikidata.wdtk.datamodel.implementation.ItemIdValueImpl;
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WbItemConstant extends WbItemExpr {
/* Represents an item that does not vary,
* it is independent of the row. */
/**
* Represents an item that does not vary,
* it is independent of the row.
*/
public class WbItemConstant implements WbValueExpr<ItemIdValue> {
private String qid;
private String label;

View File

@ -10,16 +10,22 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The representation of an item document, which can contain
* variables both for its own id and in its contents.
*
* @author antonin
*
*/
public class WbItemDocumentExpr extends JacksonJsonizable {
private WbItemExpr subject;
private WbValueExpr<? extends ItemIdValue> subject;
private List<WbNameDescExpr> nameDescs;
private List<WbStatementGroupExpr> statementGroups;
@JsonCreator
public WbItemDocumentExpr(
@JsonProperty("subject") WbItemExpr subjectExpr,
@JsonProperty("subject") WbValueExpr<? extends ItemIdValue> subjectExpr,
@JsonProperty("nameDescs") List<WbNameDescExpr> nameDescExprs,
@JsonProperty("statementGroups") List<WbStatementGroupExpr> statementGroupExprs) {
this.subject = subjectExpr;
@ -46,7 +52,7 @@ public class WbItemDocumentExpr extends JacksonJsonizable {
}
@JsonProperty("subject")
public WbItemExpr getSubject() {
public WbValueExpr<? extends ItemIdValue> getSubject() {
return subject;
}

View File

@ -1,11 +0,0 @@
package org.openrefine.wikidata.schema;
import org.openrefine.wikidata.schema.ExpressionContext;
import org.openrefine.wikidata.schema.WbValueExpr;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
public abstract class WbItemExpr extends WbValueExpr {
public abstract ItemIdValue evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException;
}

View File

@ -5,36 +5,24 @@ import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.model.Cell;
import com.google.refine.model.Recon.Judgment;
public class WbItemVariable extends WbItemExpr {
/* An item that depends on a reconciled value in a column */
private String columnName;
@JsonCreator
public WbItemVariable(
@JsonProperty("columnName") String columnName) {
this.columnName = columnName;
}
/**
* An item that depends on a reconciled value in a column.
*
* @author antonin
*
*/
public class WbItemVariable extends WbVariableExpr<ItemIdValue> {
@Override
public ItemIdValue evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException {
Cell cell = ctxt.getCellByName(getColumnName());
if (cell != null && cell.recon != null
public ItemIdValue fromCell(Cell cell, ExpressionContext ctxt) throws SkipSchemaExpressionException {
if (cell.recon != null
&& (Judgment.Matched.equals(cell.recon.judgment) ||
Judgment.New.equals(cell.recon.judgment))) {
return new ReconItemIdValue(cell.recon, cell.value.toString());
}
throw new SkipSchemaExpressionException();
}
@JsonProperty("columnName")
public String getColumnName() {
return columnName;
}
}

View File

@ -5,7 +5,15 @@ import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WbLanguageConstant extends WbLanguageExpr {
/**
* A constant that represents a Wikimedia language code.
*
* TODO: migrate to a class more specific than String, with validation.
*
* @author antonin
*
*/
public class WbLanguageConstant implements WbValueExpr<String> {
protected String _langId;
protected String _langLabel;

View File

@ -1,26 +0,0 @@
package org.openrefine.wikidata.schema;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.openrefine.wikidata.utils.JacksonJsonizable;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
include=JsonTypeInfo.As.PROPERTY,
property="type")
@JsonSubTypes({
@Type(value = WbLanguageConstant.class, name = "wblanguageconstant"),
@Type(value = WbLanguageVariable.class, name = "wblanguagevariable")
})
public abstract class WbLanguageExpr extends JacksonJsonizable {
/**
* Evaluates the language expression to a Wikimedia language code
*
* @param ctxt the evaluation context
* @return a Wikimedia language code
* @throws SkipSchemaExpressionException when the code is invalid
*/
public abstract String evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException;
}

View File

@ -7,31 +7,18 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.model.Cell;
public class WbLanguageVariable extends WbLanguageExpr {
private String columnName;
@JsonCreator
public WbLanguageVariable(
@JsonProperty("columnName") String columnName) {
this.columnName = columnName;
}
/**
* A language variable generates a language code from a cell.
*/
public class WbLanguageVariable extends WbVariableExpr<String> {
@Override
public String evaluate(ExpressionContext ctxt)
public String fromCell(Cell cell, ExpressionContext ctxt)
throws SkipSchemaExpressionException {
Cell cell = ctxt.getCellByName(getColumnName());
if (cell != null && cell.value != null && !cell.value.toString().isEmpty()) {
if (cell.value != null && !cell.value.toString().isEmpty()) {
// TODO some validation here?
return cell.value.toString();
}
throw new SkipSchemaExpressionException();
}
@JsonProperty("columnName")
public String getColumnName() {
return columnName;
}
}

View File

@ -10,7 +10,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WbLocationConstant extends WbLocationExpr {
public class WbLocationConstant implements WbValueExpr<GlobeCoordinatesValue> {
private String value;
private GlobeCoordinatesValue parsed;

View File

@ -1,10 +0,0 @@
package org.openrefine.wikidata.schema;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.GlobeCoordinatesValue;
public abstract class WbLocationExpr extends WbValueExpr {
@Override
public abstract GlobeCoordinatesValue evaluate(ExpressionContext ctxt)
throws SkipSchemaExpressionException;
}

View File

@ -5,38 +5,19 @@ import java.text.ParseException;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.GlobeCoordinatesValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.model.Cell;
public class WbLocationVariable extends WbLocationExpr {
private String columnName;
@JsonCreator
public WbLocationVariable(
@JsonProperty("columnName") String columnName) {
this.columnName = columnName;
}
public class WbLocationVariable extends WbVariableExpr<GlobeCoordinatesValue> {
@Override
public GlobeCoordinatesValue evaluate(ExpressionContext ctxt)
public GlobeCoordinatesValue fromCell(Cell cell, ExpressionContext ctxt)
throws SkipSchemaExpressionException {
Cell cell = ctxt.getCellByName(getColumnName());
if (cell != null) {
String expr = cell.value.toString();
try {
return WbLocationConstant.parse(expr);
} catch (ParseException e) {
}
String expr = cell.value.toString();
try {
return WbLocationConstant.parse(expr);
} catch (ParseException e) {
throw new SkipSchemaExpressionException();
}
throw new SkipSchemaExpressionException();
}
@JsonProperty("columnName")
public String getColumnName() {
return columnName;
}
}

View File

@ -4,20 +4,21 @@ import org.openrefine.wikidata.qa.QAWarning;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue;
import org.wikidata.wdtk.datamodel.interfaces.StringValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WbMonolingualExpr extends WbValueExpr {
public class WbMonolingualExpr implements WbValueExpr<MonolingualTextValue> {
private WbLanguageExpr languageExpr;
private WbStringExpr valueExpr;
private WbValueExpr<? extends String> languageExpr;
private WbValueExpr<? extends StringValue> valueExpr;
@JsonCreator
public WbMonolingualExpr(
@JsonProperty("language") WbLanguageExpr languageExpr,
@JsonProperty("value") WbStringExpr valueExpr) {
@JsonProperty("language") WbValueExpr<? extends String> languageExpr,
@JsonProperty("value") WbValueExpr<? extends StringValue> valueExpr) {
this.languageExpr = languageExpr;
this.valueExpr = valueExpr;
}
@ -45,12 +46,12 @@ public class WbMonolingualExpr extends WbValueExpr {
}
@JsonProperty("language")
public WbLanguageExpr getLanguageExpr() {
public WbValueExpr<? extends String> getLanguageExpr() {
return languageExpr;
}
@JsonProperty("value")
public WbStringExpr getValueExpr() {
public WbValueExpr<? extends StringValue> getValueExpr() {
return valueExpr;
}
}

View File

@ -6,9 +6,13 @@ import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WbPropConstant extends WbPropExpr {
/* A constant property, that does not change depending on the row */
/**
* A constant property, that does not change depending on the row
*
* @author antonin
*
*/
public class WbPropConstant implements WbValueExpr<PropertyIdValue> {
private String pid;
private String label;

View File

@ -1,23 +0,0 @@
package org.openrefine.wikidata.schema;
import org.json.JSONException;
import org.json.JSONObject;
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@JsonSubTypes({
@Type(value = WbPropConstant.class, name = "wbpropconstant")
})
public abstract class WbPropExpr extends WbValueExpr {
/* An expression that represents a property */
public abstract PropertyIdValue evaluate(ExpressionContext ctxt);
public static WbPropExpr fromJSON(JSONObject obj) throws JSONException {
return WbPropConstant.fromJSON(obj);
}
}

View File

@ -13,13 +13,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class WbSnakExpr extends JacksonJsonizable {
private WbPropExpr prop;
private WbValueExpr value;
private WbValueExpr<? extends PropertyIdValue> prop;
private WbValueExpr<? extends Value> value;
@JsonCreator
public WbSnakExpr(
@JsonProperty("prop") WbPropExpr propExpr,
@JsonProperty("value") WbValueExpr valueExpr) {
@JsonProperty("prop") WbValueExpr<? extends PropertyIdValue> propExpr,
@JsonProperty("value") WbValueExpr<? extends Value> valueExpr) {
this.prop = propExpr;
this.value = valueExpr;
}
@ -31,12 +31,12 @@ public class WbSnakExpr extends JacksonJsonizable {
}
@JsonProperty("prop")
public WbPropExpr getProp() {
public WbValueExpr<? extends PropertyIdValue> getProp() {
return prop;
}
@JsonProperty("value")
public WbValueExpr getValue() {
public WbValueExpr<? extends Value> getValue() {
return value;
}
}

View File

@ -30,13 +30,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class WbStatementExpr extends JacksonJsonizable {
private WbValueExpr mainSnakValueExpr;
private WbValueExpr<? extends Value> mainSnakValueExpr;
private List<WbSnakExpr> qualifierExprs;
private List<WbReferenceExpr> referenceExprs;
@JsonCreator
public WbStatementExpr(
@JsonProperty("value") WbValueExpr mainSnakValueExpr,
@JsonProperty("value") WbValueExpr<? extends Value> mainSnakValueExpr,
@JsonProperty("qualifiers") List<WbSnakExpr> qualifierExprs,
@JsonProperty("references") List<WbReferenceExpr> referenceExprs) {
this.mainSnakValueExpr = mainSnakValueExpr;
@ -99,7 +99,7 @@ public class WbStatementExpr extends JacksonJsonizable {
}
@JsonProperty("value")
public WbValueExpr getMainsnak() {
public WbValueExpr<? extends Value> getMainsnak() {
return mainSnakValueExpr;
}

View File

@ -17,12 +17,12 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class WbStatementGroupExpr extends JacksonJsonizable {
private WbPropExpr propertyExpr;
private WbValueExpr<? extends PropertyIdValue> propertyExpr;
private List<WbStatementExpr> statementExprs;
@JsonCreator
public WbStatementGroupExpr(
@JsonProperty("property") WbPropExpr propertyExpr,
@JsonProperty("property") WbValueExpr<? extends PropertyIdValue> propertyExpr,
@JsonProperty("statements") List<WbStatementExpr> claimExprs) {
this.propertyExpr = propertyExpr;
this.statementExprs = claimExprs;
@ -46,7 +46,7 @@ public class WbStatementGroupExpr extends JacksonJsonizable {
}
@JsonProperty("property")
public WbPropExpr getProperty() {
public WbValueExpr<? extends PropertyIdValue> getProperty() {
return propertyExpr;
}

View File

@ -7,7 +7,7 @@ import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WbStringConstant extends WbStringExpr {
public class WbStringConstant implements WbValueExpr<StringValue> {
private String value;

View File

@ -1,8 +0,0 @@
package org.openrefine.wikidata.schema;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.StringValue;
public abstract class WbStringExpr extends WbValueExpr {
public abstract StringValue evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException;
}

View File

@ -9,29 +9,20 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.model.Cell;
public class WbStringVariable extends WbStringExpr {
public static final String jsonType = "wbstringvariable";
private String columnName;
@JsonCreator
public WbStringVariable(
@JsonProperty("columnName") String columnName) {
this.columnName = columnName;
}
/**
* A variable that returns a simple string value.
*
* @author antonin
*
*/
public class WbStringVariable extends WbVariableExpr<StringValue> {
@Override
public StringValue evaluate(ExpressionContext ctxt)
public StringValue fromCell(Cell cell, ExpressionContext ctxt)
throws SkipSchemaExpressionException {
Cell cell = ctxt.getCellByName(columnName);
if (cell != null && !cell.value.toString().isEmpty()) {
if (!cell.value.toString().isEmpty()) {
return Datamodel.makeStringValue(cell.value.toString());
}
throw new SkipSchemaExpressionException();
}
@JsonProperty("columnName")
public String getColumnName() {
return columnName;
}
}

View File

@ -10,7 +10,10 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
/**
* The base interface for all expressions, which evaluate to a
* particular type T in an ExpressionContext.
*/
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
include=JsonTypeInfo.As.PROPERTY,
property="type")
@ -26,20 +29,15 @@ import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@Type(value = WbDateConstant.class, name = "wbdateconstant"),
@Type(value = WbDateVariable.class, name = "wbdatevariable"),
@Type(value = WbMonolingualExpr.class, name = "wbmonolingualexpr"),
@Type(value = WbPropConstant.class, name = "wbpropconstant"),
@Type(value = WbLanguageConstant.class, name = "wblanguageconstant"),
@Type(value = WbLanguageVariable.class, name = "wblanguagevariable"),
})
public abstract class WbValueExpr extends JacksonJsonizable {
/* An expression that represents a Wikibase value,
* i.e. anything that can be on the right-hand side
* of a statement.
*/
public interface WbValueExpr<T> {
/*
/**
* Evaluates the value expression in a given context,
* returns a wikibase value suitable to be the target of a claim.
* returns a Wikibase value suitable to be the target of a claim.
*/
public abstract Value evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException;
public static WbValueExpr fromJSON(JSONObject obj) throws JSONException {
return fromJSONClass(obj, WbValueExpr.class);
}
public T evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException;
}

View File

@ -0,0 +1,91 @@
package org.openrefine.wikidata.schema;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.interfaces.Value;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.model.Cell;
/**
* A base class for expressions which draw their values
* from a particular column.
*
* @author antonin
*
* @param <T>
* the type of Wikibase value returned by the expression.
*/
public abstract class WbVariableExpr<T> implements WbValueExpr<T> {
private String columnName;
/**
* Constructs a variable expression from a column name.
*
* @param columnName
* the name of the column the expression should draw its value from.
*/
@JsonCreator
public WbVariableExpr(
@JsonProperty("columnName") String columnName) {
this.columnName = columnName;
}
/**
* Constructs a variable without setting the column name yet.
*/
@JsonCreator
public WbVariableExpr() {
columnName = null;
}
/**
* Returns the column name used by the variable.
* @return
* the OpenRefine column name
*/
@JsonProperty("columnName")
public String getColumnName() {
return columnName;
}
/**
* Changes the column name used by the variable.
* This is useful for deserialization, as well as updates when
* column names change.
*/
@JsonProperty("columnName")
public void setColumnName(String columnName) {
this.columnName = columnName;
}
/**
* Evaluates the expression in a given context, returning
*/
@Override
public T evaluate(ExpressionContext ctxt)
throws SkipSchemaExpressionException {
Cell cell = ctxt.getCellByName(columnName);
if (cell != null) {
return fromCell(cell, ctxt);
}
throw new SkipSchemaExpressionException();
}
/**
* Method that should be implemented by subclasses,
* converting an OpenRefine cell to a Wikibase value.
* Access to other values and emiting warnings is possible via
* the supplied EvaluationContext object.
*
* @param cell
* the cell to convert
* @param ctxt
* the evaluation context
* @return
* the corresponding Wikibase value
*/
public abstract T fromCell(Cell cell, ExpressionContext ctxt) throws SkipSchemaExpressionException;
}