Skip update if rewriting failed

This commit is contained in:
Antonin Delpeuch 2019-11-05 17:49:47 +00:00
parent ec5c9cd418
commit de6dedb43d
4 changed files with 213 additions and 116 deletions

View File

@ -31,6 +31,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import org.openrefine.wikidata.schema.entityvalues.ReconEntityIdValue;
import org.openrefine.wikidata.schema.exceptions.NewItemNotCreatedYetException;
import org.openrefine.wikidata.updates.ItemUpdate;
import org.openrefine.wikidata.updates.scheduler.WikibaseAPIUpdateScheduler;
import org.slf4j.Logger;
@ -128,7 +129,12 @@ public class EditBatchProcessor {
// Rewrite mentions to new items
ReconEntityRewriter rewriter = new ReconEntityRewriter(library, update.getItemId());
try {
update = rewriter.rewrite(update);
} catch (NewItemNotCreatedYetException e) {
logger.warn("Failed to rewrite update on entity "+update.getItemId()+". Missing entity: "+e.getMissingEntity()+". Skipping update.");
return;
}
try {
// New item

View File

@ -28,10 +28,12 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
import org.openrefine.wikidata.schema.exceptions.NewItemNotCreatedYetException;
import org.openrefine.wikidata.updates.ItemUpdate;
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
import org.wikidata.wdtk.datamodel.helpers.DatamodelConverter;
import org.wikidata.wdtk.datamodel.implementation.DataObjectFactoryImpl;
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue;
import org.wikidata.wdtk.datamodel.interfaces.Statement;
@ -53,15 +55,19 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
*/
public class ReconEntityRewriter extends DatamodelConverter {
private NewItemLibrary library;
private ItemIdValue subject;
private final NewItemLibrary library;
private final ItemIdValue subject;
protected static final String notCreatedYetMessage = "Trying to rewrite an update where a new item was not created yet.";
/**
* Constructor. Sets up a rewriter which uses the provided library to look up
* qids of new items, and the subject (which should not be rewritten).
* qids of new items.
*
* @param library
* the collection of items already created
* @param subject
* the subject id of the entity to rewrite
*/
public ReconEntityRewriter(NewItemLibrary library, ItemIdValue subject) {
super(new DataObjectFactoryImpl());
@ -71,16 +77,16 @@ public class ReconEntityRewriter extends DatamodelConverter {
@Override
public ItemIdValue copy(ItemIdValue value) {
if (subject.equals(value)) {
return value;
}
if (value instanceof ReconItemIdValue) {
ReconItemIdValue recon = (ReconItemIdValue) value;
if (recon.isNew()) {
String newId = library.getQid(recon.getReconInternalId());
if (newId == null) {
throw new IllegalArgumentException(
"Trying to rewrite an update where a new item was not created yet.");
if (subject.equals(recon)) {
return subject;
} else {
throw new MissingEntityIdFound(recon);
}
}
return Datamodel.makeItemIdValue(newId, recon.getRecon().identifierSpace);
}
@ -88,7 +94,21 @@ public class ReconEntityRewriter extends DatamodelConverter {
return super.copy(value);
}
public ItemUpdate rewrite(ItemUpdate update) {
/**
* Rewrite an update, replacing references to all entities already
* created by their fresh identifiers. The subject id might not have been
* created already, in which case it will be left untouched. All the other
* entities need to have been created already.
*
* @param update
* the update to rewrite
* @return
* the rewritten update
* @throws NewItemNotCreatedYetException
* if any non-subject entity had not been created yet
*/
public ItemUpdate rewrite(ItemUpdate update) throws NewItemNotCreatedYetException {
try {
ItemIdValue subject = copy(update.getItemId());
Set<MonolingualTextValue> labels = update.getLabels().stream().map(l -> copy(l)).collect(Collectors.toSet());
Set<MonolingualTextValue> labelsIfNew = update.getLabelsIfNew().stream().map(l -> copy(l)).collect(Collectors.toSet());
@ -102,5 +122,20 @@ public class ReconEntityRewriter extends DatamodelConverter {
Set<Statement> deletedStatements = update.getDeletedStatements().stream().map(l -> copy(l))
.collect(Collectors.toSet());
return new ItemUpdate(subject, addedStatements, deletedStatements, labels, labelsIfNew, descriptions, descriptionsIfNew, aliases);
} catch(MissingEntityIdFound e) {
throw new NewItemNotCreatedYetException(e.value);
}
}
/**
* Unchecked version of {@class NewItemNotCreatedYetException}, for internal use only.
*/
protected static class MissingEntityIdFound extends Error {
private static final long serialVersionUID = 1L;
protected EntityIdValue value;
public MissingEntityIdFound(EntityIdValue missing) {
this.value = missing;
}
}
}

View File

@ -0,0 +1,19 @@
package org.openrefine.wikidata.schema.exceptions;
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
public class NewItemNotCreatedYetException extends Exception {
private static final long serialVersionUID = -563535295696710197L;
private final EntityIdValue value;
public NewItemNotCreatedYetException(EntityIdValue value) {
super("Attempted to rewrite an entity which was not created yet: "+value);
this.value = value;
}
public EntityIdValue getMissingEntity() {
return value;
}
}

View File

@ -25,6 +25,7 @@ package org.openrefine.wikidata.editing;
import static org.testng.Assert.assertEquals;
import org.openrefine.wikidata.schema.exceptions.NewItemNotCreatedYetException;
import org.openrefine.wikidata.testing.TestingData;
import org.openrefine.wikidata.updates.ItemUpdate;
import org.openrefine.wikidata.updates.ItemUpdateBuilder;
@ -37,38 +38,51 @@ public class ReconEntityRewriterTest {
NewItemLibrary library = null;
ReconEntityRewriter rewriter = null;
ItemIdValue subject = TestingData.newIdA;
ItemIdValue newlyCreated = Datamodel.makeWikidataItemIdValue("Q1234");
@BeforeMethod
public void setUp() {
library = new NewItemLibrary();
rewriter = new ReconEntityRewriter(library, subject);
}
@Test(expectedExceptions = IllegalArgumentException.class)
@Test(expectedExceptions = ReconEntityRewriter.MissingEntityIdFound.class)
public void testNotCreatedYet() {
rewriter = new ReconEntityRewriter(library, TestingData.newIdA);
rewriter.copy(TestingData.newIdB);
}
@Test
public void testSuccessfulRewrite() {
rewriter = new ReconEntityRewriter(library, TestingData.newIdA);
library.setQid(4567L, "Q1234");
assertEquals(newlyCreated, rewriter.copy(TestingData.newIdB));
}
@Test
public void testSubjectNotRewriten() {
public void testSubjectNotRewritten() {
ItemIdValue subject = TestingData.newIdA;
rewriter = new ReconEntityRewriter(library, subject);
assertEquals(subject, rewriter.copy(subject));
}
@Test
public void testSubjectRewritten() {
ItemIdValue subject = TestingData.newIdB;
library.setQid(4567L, "Q1234");
rewriter = new ReconEntityRewriter(library, subject);
assertEquals(newlyCreated, rewriter.copy(subject));
}
@Test
public void testMatched() {
rewriter = new ReconEntityRewriter(library, TestingData.newIdA);
assertEquals(TestingData.matchedId, rewriter.copy(TestingData.matchedId));
}
@Test
public void testRewriteUpdate() {
public void testRewriteCreate() throws NewItemNotCreatedYetException {
ItemIdValue subject = TestingData.newIdA;
rewriter = new ReconEntityRewriter(library, subject);
library.setQid(4567L, "Q1234");
ItemUpdate update = new ItemUpdateBuilder(subject)
.addStatement(TestingData.generateStatement(subject, TestingData.newIdB))
@ -87,7 +101,9 @@ public class ReconEntityRewriterTest {
}
@Test
public void testRewriteCreation() {
public void testRewriteUpdateOnPreviouslyCreatedEntity() throws NewItemNotCreatedYetException {
ItemIdValue subject = TestingData.newIdA;
rewriter = new ReconEntityRewriter(library, subject);
library.setQid(4567L, "Q1234");
ItemUpdate update = new ItemUpdateBuilder(TestingData.newIdB)
.addDescription(Datamodel.makeMonolingualTextValue("beschreibung", "de"), false)
@ -98,4 +114,25 @@ public class ReconEntityRewriterTest {
.addAlias(Datamodel.makeMonolingualTextValue("darstellung", "de")).build();
assertEquals(rewritten, expected);
}
@Test
public void testRewriteUpdateOnExistingEntity() throws NewItemNotCreatedYetException {
ItemIdValue subject = TestingData.matchedId;
rewriter = new ReconEntityRewriter(library, subject);
library.setQid(4567L, "Q1234");
ItemUpdate update = new ItemUpdateBuilder(subject)
.addStatement(TestingData.generateStatement(subject, TestingData.newIdB))
.deleteStatement(TestingData.generateStatement(subject, TestingData.existingId))
.addLabel(Datamodel.makeMonolingualTextValue("label", "de"), true)
.addDescription(Datamodel.makeMonolingualTextValue("beschreibung", "de"), false)
.addAlias(Datamodel.makeMonolingualTextValue("darstellung", "de")).build();
ItemUpdate rewritten = rewriter.rewrite(update);
ItemUpdate expected = new ItemUpdateBuilder(subject)
.addStatement(TestingData.generateStatement(subject, newlyCreated))
.deleteStatement(TestingData.generateStatement(subject, TestingData.existingId))
.addLabel(Datamodel.makeMonolingualTextValue("label", "de"), true)
.addDescription(Datamodel.makeMonolingualTextValue("beschreibung", "de"), false)
.addAlias(Datamodel.makeMonolingualTextValue("darstellung", "de")).build();
assertEquals(rewritten, expected);
}
}