Add quantity expressions in the backend

This commit is contained in:
Antonin Delpeuch 2018-02-24 11:44:15 +00:00
parent 487547bd27
commit 1837926cb1
4 changed files with 141 additions and 0 deletions

View File

@ -185,6 +185,7 @@ public class QuickStatementsExporter implements WriterExporter {
String unit = value.getUnit();
if (!unit.startsWith(unitPrefix))
return null; // QuickStatements only accepts Qids as units
// TODO test this for values without bounds
String unitID = "U"+unit.substring(unitPrefix.length());
return String.format(
Locale.US,

View File

@ -28,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@Type(value = WbPropConstant.class, name = "wbpropconstant"),
@Type(value = WbLanguageConstant.class, name = "wblanguageconstant"),
@Type(value = WbLanguageVariable.class, name = "wblanguagevariable"),
@Type(value = WbQuantityExpr.class, name="wbquantityexpr"),
})
public interface WbExpression<T> {

View File

@ -0,0 +1,71 @@
package org.openrefine.wikidata.schema;
import java.math.BigDecimal;
import java.util.regex.Pattern;
import org.apache.commons.lang.Validate;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
import org.wikidata.wdtk.datamodel.interfaces.QuantityValue;
import org.wikidata.wdtk.datamodel.interfaces.StringValue;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class WbQuantityExpr implements WbExpression<QuantityValue> {
private final WbExpression<? extends StringValue> amountExpr;
private final WbExpression<? extends ItemIdValue> unitExpr;
/**
* Creates an expression for a quantity, which
* contains two sub-expressions: one for the amount (a string with
* a particular format) and one for the unit, which is optional.
*
* Setting unitExpr to null will give quantities without units. Setting
* it to a non-null value will make the unit mandatory: if the unit expression
* fails to evaluate, the whole quantity expression will fail too.
*/
@JsonCreator
public WbQuantityExpr(
@JsonProperty("amount") WbExpression<? extends StringValue> amountExpr,
@JsonProperty("unit") WbExpression<? extends ItemIdValue> unitExpr) {
Validate.notNull(amountExpr);
this.amountExpr = amountExpr;
this.unitExpr = unitExpr;
}
@Override
public QuantityValue evaluate(ExpressionContext ctxt)
throws SkipSchemaExpressionException {
StringValue amount = getLanguageExpr().evaluate(ctxt);
if (amount == null || amount.getString().isEmpty()) {
throw new SkipSchemaExpressionException();
}
BigDecimal parsedAmount = null;
try {
parsedAmount = new BigDecimal(amount.getString());
} catch(NumberFormatException e) {
throw new SkipSchemaExpressionException();
}
if(getUnitExpr() != null) {
ItemIdValue unit = getUnitExpr().evaluate(ctxt);
return Datamodel.makeQuantityValue(parsedAmount, unit.getIri());
}
return Datamodel.makeQuantityValue(parsedAmount);
}
@JsonProperty("amount")
public WbExpression<? extends StringValue> getLanguageExpr() {
return amountExpr;
}
@JsonProperty("unit")
public WbExpression<? extends ItemIdValue> getUnitExpr() {
return unitExpr;
}
}

View File

@ -0,0 +1,68 @@
package org.openrefine.wikidata.schema;
import java.io.IOException;
import java.math.BigDecimal;
import org.openrefine.wikidata.qa.QAWarningStore;
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
import com.google.refine.model.ModelException;
import com.google.refine.model.Project;
import com.google.refine.model.Row;
import com.google.refine.tests.RefineTest;
public class WbQuantityValueTest extends RefineTest {
protected Project project;
protected Row row;
protected ExpressionContext ctxt;
protected QAWarningStore warningStore;
@BeforeMethod
public void createProject() throws IOException, ModelException {
project = createCSVProject("Wikidata quantity value test project",
"column A\nrow1");
warningStore = new QAWarningStore();
row = project.rows.get(0);
ctxt = new ExpressionContext("http://www.wikidata.org/entity/", 0,
row, project.columnModel, warningStore);
}
@Test
public void testWithoutUnit() throws SkipSchemaExpressionException {
WbQuantityExpr expr = new WbQuantityExpr(new WbStringConstant("4.00"), null);
Assert.assertEquals(Datamodel.makeQuantityValue(new BigDecimal("4.00"), null, null, "1"), expr.evaluate(ctxt));
}
@Test(expectedExceptions = SkipSchemaExpressionException.class)
public void testInvalidAmountWithoutUnit() throws SkipSchemaExpressionException {
WbQuantityExpr expr = new WbQuantityExpr(new WbStringConstant("hello"), null);
expr.evaluate(ctxt);
}
@Test
public void testWithUnit() throws SkipSchemaExpressionException {
WbItemConstant item = new WbItemConstant("Q42", "label");
WbQuantityExpr expr = new WbQuantityExpr(new WbStringConstant("56.094"), item);
Assert.assertEquals(Datamodel.makeQuantityValue(new BigDecimal("56.094"), null, null, "http://www.wikidata.org/entity/Q42"), expr.evaluate(ctxt));
}
@Test(expectedExceptions = SkipSchemaExpressionException.class)
public void testInvalidAmountWithUnit() throws SkipSchemaExpressionException {
WbItemConstant item = new WbItemConstant("Q42", "label");
WbQuantityExpr expr = new WbQuantityExpr(new WbStringConstant("invalid"), item);
expr.evaluate(ctxt);
}
@Test(expectedExceptions = SkipSchemaExpressionException.class)
public void testInvalidUnitWithAmount() throws SkipSchemaExpressionException {
WbItemVariable item = new WbItemVariable();
item.setColumnName("column A");
WbQuantityExpr expr = new WbQuantityExpr(new WbStringConstant("56.094"), item);
expr.evaluate(ctxt);
}
}