Add license headers, general cleanups on Java files
This commit is contained in:
parent
d6b229f25e
commit
0b14a1a627
@ -1,10 +1,32 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Copyright (C) 2018 Antonin Delpeuch
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
Sources for the images:
|
|
||||||
- Information.svg by User:Bobarino:
|
The following images were obtained from Wikimedia Commons:
|
||||||
|
- Information.svg by User:Bobarino: (CC BY-SA)
|
||||||
https://commons.wikimedia.org/wiki/File:Information.svg
|
https://commons.wikimedia.org/wiki/File:Information.svg
|
||||||
- Warning.svg by User:Ezekiel63745
|
- Warning.svg by User:Ezekiel63745 (CC BY-SA)
|
||||||
https://commons.wikimedia.org/wiki/File:Information_orange.svg
|
https://commons.wikimedia.org/wiki/File:Information_orange.svg
|
||||||
- Important.svg originally from David Vignoni
|
- Important.svg originally from David Vignoni (GNU LGPL)
|
||||||
https://commons.wikimedia.org/wiki/File:Nuvola_apps_important.svg
|
https://commons.wikimedia.org/wiki/File:Nuvola_apps_important.svg
|
||||||
- Critical.svg by User:Stannered
|
- Critical.svg by User:Stannered (CC BY-SA)
|
||||||
https://commons.wikimedia.org/wiki/File:Stop_x_nuvola.svg
|
https://commons.wikimedia.org/wiki/File:Stop_x_nuvola.svg
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -14,13 +37,13 @@ import org.openrefine.wikidata.editing.ConnectionManager;
|
|||||||
import com.google.refine.commands.Command;
|
import com.google.refine.commands.Command;
|
||||||
|
|
||||||
public class LoginCommand extends Command {
|
public class LoginCommand extends Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
String username = request.getParameter("wb-username");
|
String username = request.getParameter("wb-username");
|
||||||
String password = request.getParameter("wb-password");
|
String password = request.getParameter("wb-password");
|
||||||
String remember = request.getParameter("remember-credentials");
|
String remember = request.getParameter("remember-credentials");
|
||||||
System.out.println(remember);
|
|
||||||
ConnectionManager manager = ConnectionManager.getInstance();
|
ConnectionManager manager = ConnectionManager.getInstance();
|
||||||
if (username != null && password != null) {
|
if (username != null && password != null) {
|
||||||
manager.login(username, password, "on".equals(remember));
|
manager.login(username, password, "on".equals(remember));
|
||||||
@ -29,10 +52,10 @@ public class LoginCommand extends Command {
|
|||||||
}
|
}
|
||||||
response.setCharacterEncoding("UTF-8");
|
response.setCharacterEncoding("UTF-8");
|
||||||
response.setHeader("Content-Type", "application/json");
|
response.setHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
StringWriter sb = new StringWriter(2048);
|
StringWriter sb = new StringWriter(2048);
|
||||||
JSONWriter writer = new JSONWriter(sb);
|
JSONWriter writer = new JSONWriter(sb);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writer.object();
|
writer.object();
|
||||||
writer.key("logged_in");
|
writer.key("logged_in");
|
||||||
@ -45,7 +68,7 @@ public class LoginCommand extends Command {
|
|||||||
}
|
}
|
||||||
respond(response, sb.toString());
|
respond(response, sb.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@ -15,8 +38,7 @@ public class PerformWikibaseEditsCommand extends EngineDependentCommand {
|
|||||||
protected AbstractOperation createOperation(Project project, HttpServletRequest request, JSONObject engineConfig)
|
protected AbstractOperation createOperation(Project project, HttpServletRequest request, JSONObject engineConfig)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
String summary = request.getParameter("summary");
|
String summary = request.getParameter("summary");
|
||||||
return new PerformWikibaseEditsOperation(engineConfig,
|
return new PerformWikibaseEditsOperation(engineConfig, summary);
|
||||||
summary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright 2010, Google Inc.
|
Copyright 2010, Google Inc.
|
||||||
@ -34,8 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.LineNumberReader;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@ -63,25 +84,25 @@ import com.google.refine.model.Project;
|
|||||||
import com.google.refine.util.ParsingUtilities;
|
import com.google.refine.util.ParsingUtilities;
|
||||||
|
|
||||||
public class PreviewWikibaseSchemaCommand extends Command {
|
public class PreviewWikibaseSchemaCommand extends Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Project project = getProject(request);
|
Project project = getProject(request);
|
||||||
|
|
||||||
response.setCharacterEncoding("UTF-8");
|
response.setCharacterEncoding("UTF-8");
|
||||||
response.setHeader("Content-Type", "application/json");
|
response.setHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
String jsonString = request.getParameter("schema");
|
String jsonString = request.getParameter("schema");
|
||||||
|
|
||||||
|
|
||||||
WikibaseSchema schema = null;
|
WikibaseSchema schema = null;
|
||||||
if (jsonString != null) {
|
if (jsonString != null) {
|
||||||
try {
|
try {
|
||||||
JSONObject json = ParsingUtilities.evaluateJsonStringToObject(jsonString);
|
JSONObject json = ParsingUtilities.evaluateJsonStringToObject(jsonString);
|
||||||
schema = WikibaseSchema.reconstruct(json);
|
schema = WikibaseSchema.reconstruct(json);
|
||||||
} catch(JSONException e) {
|
} catch (JSONException e) {
|
||||||
respond(response, "error", "Wikibase schema could not be parsed.");
|
respond(response, "error", "Wikibase schema could not be parsed.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -92,20 +113,20 @@ public class PreviewWikibaseSchemaCommand extends Command {
|
|||||||
respond(response, "error", "No Wikibase schema provided.");
|
respond(response, "error", "No Wikibase schema provided.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QAWarningStore warningStore = new QAWarningStore();
|
QAWarningStore warningStore = new QAWarningStore();
|
||||||
|
|
||||||
// Evaluate project
|
// Evaluate project
|
||||||
Engine engine = getEngine(request, project);
|
Engine engine = getEngine(request, project);
|
||||||
List<ItemUpdate> editBatch = schema.evaluate(project, engine, warningStore);
|
List<ItemUpdate> editBatch = schema.evaluate(project, engine, warningStore);
|
||||||
|
|
||||||
StringWriter sb = new StringWriter(2048);
|
StringWriter sb = new StringWriter(2048);
|
||||||
JSONWriter writer = new JSONWriter(sb);
|
JSONWriter writer = new JSONWriter(sb);
|
||||||
writer.object();
|
writer.object();
|
||||||
|
|
||||||
{
|
{
|
||||||
StringWriter stringWriter = new StringWriter();
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
|
||||||
// Inspect the edits and generate warnings
|
// Inspect the edits and generate warnings
|
||||||
EditInspector inspector = new EditInspector(warningStore);
|
EditInspector inspector = new EditInspector(warningStore);
|
||||||
inspector.inspect(editBatch);
|
inspector.inspect(editBatch);
|
||||||
@ -115,22 +136,22 @@ public class PreviewWikibaseSchemaCommand extends Command {
|
|||||||
warning.write(writer, new Properties());
|
warning.write(writer, new Properties());
|
||||||
}
|
}
|
||||||
writer.endArray();
|
writer.endArray();
|
||||||
|
|
||||||
// this is not the length of the warnings array written before,
|
// this is not the length of the warnings array written before,
|
||||||
// but the total number of issues raised (before deduplication)
|
// but the total number of issues raised (before deduplication)
|
||||||
writer.key("nb_warnings");
|
writer.key("nb_warnings");
|
||||||
writer.value(warningStore.getNbWarnings());
|
writer.value(warningStore.getNbWarnings());
|
||||||
|
|
||||||
// Export to QuickStatements
|
// Export to QuickStatements
|
||||||
QuickStatementsExporter exporter = new QuickStatementsExporter();
|
QuickStatementsExporter exporter = new QuickStatementsExporter();
|
||||||
exporter.translateItemList(editBatch, stringWriter);
|
exporter.translateItemList(editBatch, stringWriter);
|
||||||
|
|
||||||
writer.key("quickstatements");
|
writer.key("quickstatements");
|
||||||
writer.value(FirstLinesExtractor.extractFirstLines(stringWriter.toString(), 50));
|
writer.value(FirstLinesExtractor.extractFirstLines(stringWriter.toString(), 50));
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
|
|
||||||
respond(response, sb.toString());
|
respond(response, sb.toString());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
respondException(response, e);
|
respondException(response, e);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -23,24 +46,24 @@ public class SaveWikibaseSchemaCommand extends Command {
|
|||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Project project = getProject(request);
|
Project project = getProject(request);
|
||||||
|
|
||||||
String jsonString = request.getParameter("schema");
|
String jsonString = request.getParameter("schema");
|
||||||
if (jsonString == null) {
|
if (jsonString == null) {
|
||||||
respond(response, "error", "No Wikibase schema provided.");
|
respond(response, "error", "No Wikibase schema provided.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject json = ParsingUtilities.evaluateJsonStringToObject(jsonString);
|
JSONObject json = ParsingUtilities.evaluateJsonStringToObject(jsonString);
|
||||||
WikibaseSchema schema = WikibaseSchema.reconstruct(json);
|
WikibaseSchema schema = WikibaseSchema.reconstruct(json);
|
||||||
|
|
||||||
AbstractOperation op = new SaveWikibaseSchemaOperation(schema);
|
AbstractOperation op = new SaveWikibaseSchemaOperation(schema);
|
||||||
Process process = op.createProcess(project, new Properties());
|
Process process = op.createProcess(project, new Properties());
|
||||||
|
|
||||||
performProcessAndRespond(request, response, project, process);
|
performProcessAndRespond(request, response, project, process);
|
||||||
|
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
respond(response, "error", "Wikibase schema could not be parsed.");
|
respond(response, "error", "Wikibase schema could not be parsed.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -1,54 +1,74 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
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.wikidata.wdtk.wikibaseapi.ApiConnection;
|
import org.wikidata.wdtk.wikibaseapi.ApiConnection;
|
||||||
import org.wikidata.wdtk.wikibaseapi.LoginFailedException;
|
import org.wikidata.wdtk.wikibaseapi.LoginFailedException;
|
||||||
|
|
||||||
import com.google.refine.ProjectManager;
|
import com.google.refine.ProjectManager;
|
||||||
import com.google.refine.preference.PreferenceStore;
|
import com.google.refine.preference.PreferenceStore;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages a connection to Wikidata, with login credentials stored
|
* Manages a connection to Wikidata, with login credentials stored in the
|
||||||
* in the preferences.
|
* preferences.
|
||||||
*
|
*
|
||||||
* Ideally, we should store only the cookies and not the password.
|
* Ideally, we should store only the cookies and not the password. But
|
||||||
* But Wikidata-Toolkit does not allow for that as cookies are kept
|
* Wikidata-Toolkit does not allow for that as cookies are kept private.
|
||||||
* private.
|
|
||||||
*
|
*
|
||||||
* This class is also hard-coded for Wikidata: generalization to other
|
* This class is also hard-coded for Wikidata: generalization to other Wikibase
|
||||||
* Wikibase instances should be feasible though.
|
* instances should be feasible though.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ConnectionManager {
|
public class ConnectionManager {
|
||||||
|
|
||||||
public static final String PREFERENCE_STORE_KEY = "wikidata_credentials";
|
public static final String PREFERENCE_STORE_KEY = "wikidata_credentials";
|
||||||
|
|
||||||
private PreferenceStore prefStore;
|
private PreferenceStore prefStore;
|
||||||
private ApiConnection connection;
|
private ApiConnection connection;
|
||||||
|
|
||||||
private static class ConnectionManagerHolder {
|
private static class ConnectionManagerHolder {
|
||||||
|
|
||||||
private static final ConnectionManager instance = new ConnectionManager();
|
private static final ConnectionManager instance = new ConnectionManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConnectionManager getInstance() {
|
public static ConnectionManager getInstance() {
|
||||||
return ConnectionManagerHolder.instance;
|
return ConnectionManagerHolder.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConnectionManager() {
|
private ConnectionManager() {
|
||||||
prefStore = ProjectManager.singleton.getPreferenceStore();
|
prefStore = ProjectManager.singleton.getPreferenceStore();
|
||||||
connection = null;
|
connection = null;
|
||||||
restoreSavedConnection();
|
restoreSavedConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void login(String username, String password, boolean rememberCredentials) {
|
public void login(String username, String password, boolean rememberCredentials) {
|
||||||
if (rememberCredentials) {
|
if (rememberCredentials) {
|
||||||
try {
|
try {
|
||||||
@ -63,7 +83,7 @@ public class ConnectionManager {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connection = ApiConnection.getWikidataApiConnection();
|
connection = ApiConnection.getWikidataApiConnection();
|
||||||
try {
|
try {
|
||||||
connection.login(username, password);
|
connection.login(username, password);
|
||||||
@ -71,14 +91,13 @@ public class ConnectionManager {
|
|||||||
connection = null;
|
connection = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restoreSavedConnection() {
|
public void restoreSavedConnection() {
|
||||||
JSONObject savedCredentials = getStoredCredentials();
|
JSONObject savedCredentials = getStoredCredentials();
|
||||||
if (savedCredentials != null) {
|
if (savedCredentials != null) {
|
||||||
connection = ApiConnection.getWikidataApiConnection();
|
connection = ApiConnection.getWikidataApiConnection();
|
||||||
try {
|
try {
|
||||||
connection.login(savedCredentials.getString("username"),
|
connection.login(savedCredentials.getString("username"), savedCredentials.getString("password"));
|
||||||
savedCredentials.getString("password"));
|
|
||||||
} catch (LoginFailedException e) {
|
} catch (LoginFailedException e) {
|
||||||
connection = null;
|
connection = null;
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
@ -86,7 +105,7 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject getStoredCredentials() {
|
public JSONObject getStoredCredentials() {
|
||||||
JSONArray array = (JSONArray) prefStore.get(PREFERENCE_STORE_KEY);
|
JSONArray array = (JSONArray) prefStore.get(PREFERENCE_STORE_KEY);
|
||||||
if (array.length() > 0) {
|
if (array.length() > 0) {
|
||||||
@ -94,11 +113,11 @@ public class ConnectionManager {
|
|||||||
return array.getJSONObject(0);
|
return array.getJSONObject(0);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logout() {
|
public void logout() {
|
||||||
prefStore.put(PREFERENCE_STORE_KEY, new JSONArray());
|
prefStore.put(PREFERENCE_STORE_KEY, new JSONArray());
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
@ -110,11 +129,11 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApiConnection getConnection() {
|
public ApiConnection getConnection() {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLoggedIn() {
|
public boolean isLoggedIn() {
|
||||||
return connection != null;
|
return connection != null;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -27,184 +50,161 @@ import org.wikidata.wdtk.wikibaseapi.apierrors.MediaWikiApiErrorException;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class EditBatchProcessor {
|
public class EditBatchProcessor {
|
||||||
|
|
||||||
static final Logger logger = LoggerFactory
|
|
||||||
.getLogger(EditBatchProcessor.class);
|
|
||||||
|
|
||||||
private WikibaseDataFetcher fetcher;
|
static final Logger logger = LoggerFactory.getLogger(EditBatchProcessor.class);
|
||||||
private WikibaseDataEditor editor;
|
|
||||||
private NewItemLibrary library;
|
|
||||||
private List<ItemUpdate> scheduled;
|
|
||||||
private String summary;
|
|
||||||
|
|
||||||
private List<ItemUpdate> remainingUpdates;
|
|
||||||
private List<ItemUpdate> currentBatch;
|
|
||||||
private int batchCursor;
|
|
||||||
private int globalCursor;
|
|
||||||
private Map<String, EntityDocument> currentDocs;
|
|
||||||
private int batchSize;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiates the process of pushing a batch of updates
|
|
||||||
* to Wikibase. This schedules the updates and is a
|
|
||||||
* prerequisite for calling {@link performOneEdit}.
|
|
||||||
*
|
|
||||||
* @param fetcher
|
|
||||||
* the fetcher to use to retrieve the current state of items
|
|
||||||
* @param editor
|
|
||||||
* the object to use to perform the edits
|
|
||||||
* @param updates
|
|
||||||
* the list of item updates to perform
|
|
||||||
* @param library
|
|
||||||
* the library to use to keep track of new item creation
|
|
||||||
* @param summary
|
|
||||||
* the summary to append to all edits
|
|
||||||
* @param batchSize
|
|
||||||
* the number of items that should be retrieved in one go from the API
|
|
||||||
*/
|
|
||||||
public EditBatchProcessor(WikibaseDataFetcher fetcher,
|
|
||||||
WikibaseDataEditor editor,
|
|
||||||
List<ItemUpdate> updates,
|
|
||||||
NewItemLibrary library,
|
|
||||||
String summary,
|
|
||||||
int batchSize) {
|
|
||||||
this.fetcher = fetcher;
|
|
||||||
this.editor = editor;
|
|
||||||
editor.setEditAsBot(true); // this will not do anything if the user does not
|
|
||||||
// have a bot flag, and this is generally wanted if they have one.
|
|
||||||
this.library = library;
|
|
||||||
this.summary = summary;
|
|
||||||
this.batchSize = batchSize;
|
|
||||||
|
|
||||||
// Schedule the edit batch
|
|
||||||
WikibaseAPIUpdateScheduler scheduler = new WikibaseAPIUpdateScheduler();
|
|
||||||
this.scheduled = scheduler.schedule(updates);
|
|
||||||
this.globalCursor = 0;
|
|
||||||
|
|
||||||
this.batchCursor = 0;
|
|
||||||
this.remainingUpdates = new ArrayList<>(scheduled);
|
|
||||||
this.currentBatch = Collections.emptyList();
|
|
||||||
this.currentDocs = Collections.emptyMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private WikibaseDataFetcher fetcher;
|
||||||
/**
|
private WikibaseDataEditor editor;
|
||||||
* Performs the next edit in the batch.
|
private NewItemLibrary library;
|
||||||
*
|
private List<ItemUpdate> scheduled;
|
||||||
* @throws InterruptedException
|
private String summary;
|
||||||
*/
|
|
||||||
public void performEdit() throws InterruptedException {
|
private List<ItemUpdate> remainingUpdates;
|
||||||
if (remainingEdits() == 0) {
|
private List<ItemUpdate> currentBatch;
|
||||||
return;
|
private int batchCursor;
|
||||||
}
|
private int globalCursor;
|
||||||
if (batchCursor == currentBatch.size()) {
|
private Map<String, EntityDocument> currentDocs;
|
||||||
prepareNewBatch();
|
private int batchSize;
|
||||||
}
|
|
||||||
ItemUpdate update = currentBatch.get(batchCursor);
|
/**
|
||||||
|
* Initiates the process of pushing a batch of updates to Wikibase. This
|
||||||
// Rewrite mentions to new items
|
* schedules the updates and is a prerequisite for calling
|
||||||
ReconEntityRewriter rewriter = new ReconEntityRewriter(library, update.getItemId());
|
* {@link performOneEdit}.
|
||||||
update = rewriter.rewrite(update);
|
*
|
||||||
|
* @param fetcher
|
||||||
try {
|
* the fetcher to use to retrieve the current state of items
|
||||||
// New item
|
* @param editor
|
||||||
if (update.isNew()) {
|
* the object to use to perform the edits
|
||||||
ReconEntityIdValue newCell = (ReconEntityIdValue)update.getItemId();
|
* @param updates
|
||||||
update = update.normalizeLabelsAndAliases();
|
* the list of item updates to perform
|
||||||
|
* @param library
|
||||||
ItemDocument itemDocument = Datamodel.makeItemDocument(update.getItemId(),
|
* the library to use to keep track of new item creation
|
||||||
update.getLabels().stream().collect(Collectors.toList()),
|
* @param summary
|
||||||
update.getDescriptions().stream().collect(Collectors.toList()),
|
* the summary to append to all edits
|
||||||
update.getAliases().stream().collect(Collectors.toList()),
|
* @param batchSize
|
||||||
update.getAddedStatementGroups(),
|
* the number of items that should be retrieved in one go from the
|
||||||
Collections.emptyMap());
|
* API
|
||||||
|
*/
|
||||||
ItemDocument createdDoc = editor.createItemDocument(itemDocument, summary);
|
public EditBatchProcessor(WikibaseDataFetcher fetcher, WikibaseDataEditor editor, List<ItemUpdate> updates,
|
||||||
library.setQid(newCell.getReconInternalId(), createdDoc.getItemId().getId());
|
NewItemLibrary library, String summary, int batchSize) {
|
||||||
} else {
|
this.fetcher = fetcher;
|
||||||
// Existing item
|
this.editor = editor;
|
||||||
ItemDocument currentDocument = (ItemDocument)currentDocs.get(update.getItemId().getId());
|
editor.setEditAsBot(true); // this will not do anything if the user does not
|
||||||
/*
|
// have a bot flag, and this is generally wanted if they have one.
|
||||||
TermStatementUpdate tsUpdate = new TermStatementUpdate(
|
this.library = library;
|
||||||
currentDocument,
|
this.summary = summary;
|
||||||
update.getAddedStatements().stream().collect(Collectors.toList()),
|
this.batchSize = batchSize;
|
||||||
update.getDeletedStatements().stream().collect(Collectors.toList()),
|
|
||||||
update.getLabels().stream().collect(Collectors.toList()),
|
// Schedule the edit batch
|
||||||
update.getDescriptions().stream().collect(Collectors.toList()),
|
WikibaseAPIUpdateScheduler scheduler = new WikibaseAPIUpdateScheduler();
|
||||||
update.getAliases().stream().collect(Collectors.toList()),
|
this.scheduled = scheduler.schedule(updates);
|
||||||
new ArrayList<MonolingualTextValue>()
|
this.globalCursor = 0;
|
||||||
);
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
this.batchCursor = 0;
|
||||||
logger.info(mapper.writeValueAsString(update));
|
this.remainingUpdates = new ArrayList<>(scheduled);
|
||||||
logger.info(update.toString());
|
this.currentBatch = Collections.emptyList();
|
||||||
logger.info(tsUpdate.getJsonUpdateString()); */
|
this.currentDocs = Collections.emptyMap();
|
||||||
editor.updateTermsStatements(currentDocument,
|
}
|
||||||
update.getLabels().stream().collect(Collectors.toList()),
|
|
||||||
update.getDescriptions().stream().collect(Collectors.toList()),
|
/**
|
||||||
update.getAliases().stream().collect(Collectors.toList()),
|
* Performs the next edit in the batch.
|
||||||
new ArrayList<MonolingualTextValue>(),
|
*
|
||||||
update.getAddedStatements().stream().collect(Collectors.toList()),
|
* @throws InterruptedException
|
||||||
update.getDeletedStatements().stream().collect(Collectors.toList()),
|
*/
|
||||||
summary);
|
public void performEdit()
|
||||||
}
|
throws InterruptedException {
|
||||||
} catch (MediaWikiApiErrorException e) {
|
if (remainingEdits() == 0) {
|
||||||
// TODO find a way to report these errors to the user in a nice way
|
return;
|
||||||
e.printStackTrace();
|
}
|
||||||
} catch (IOException e) {
|
if (batchCursor == currentBatch.size()) {
|
||||||
e.printStackTrace();
|
prepareNewBatch();
|
||||||
}
|
}
|
||||||
|
ItemUpdate update = currentBatch.get(batchCursor);
|
||||||
batchCursor++;
|
|
||||||
}
|
// Rewrite mentions to new items
|
||||||
|
ReconEntityRewriter rewriter = new ReconEntityRewriter(library, update.getItemId());
|
||||||
/**
|
update = rewriter.rewrite(update);
|
||||||
* @return the number of edits that remain to be done in the current batch
|
|
||||||
*/
|
try {
|
||||||
public int remainingEdits() {
|
// New item
|
||||||
return scheduled.size() - (globalCursor + batchCursor);
|
if (update.isNew()) {
|
||||||
}
|
ReconEntityIdValue newCell = (ReconEntityIdValue) update.getItemId();
|
||||||
|
update = update.normalizeLabelsAndAliases();
|
||||||
/**
|
|
||||||
* @return the progress, measured as a percentage
|
ItemDocument itemDocument = Datamodel.makeItemDocument(update.getItemId(),
|
||||||
*/
|
update.getLabels().stream().collect(Collectors.toList()),
|
||||||
public int progress() {
|
update.getDescriptions().stream().collect(Collectors.toList()),
|
||||||
return (100*(globalCursor + batchCursor)) / scheduled.size();
|
update.getAliases().stream().collect(Collectors.toList()), update.getAddedStatementGroups(),
|
||||||
}
|
Collections.emptyMap());
|
||||||
|
|
||||||
protected void prepareNewBatch() throws InterruptedException {
|
ItemDocument createdDoc = editor.createItemDocument(itemDocument, summary);
|
||||||
// remove the previous batch from the remainingUpdates
|
library.setQid(newCell.getReconInternalId(), createdDoc.getItemId().getId());
|
||||||
globalCursor += currentBatch.size();
|
} else {
|
||||||
currentBatch.clear();
|
// Existing item
|
||||||
|
ItemDocument currentDocument = (ItemDocument) currentDocs.get(update.getItemId().getId());
|
||||||
if(remainingUpdates.size() < batchSize) {
|
editor.updateTermsStatements(currentDocument, update.getLabels().stream().collect(Collectors.toList()),
|
||||||
|
update.getDescriptions().stream().collect(Collectors.toList()),
|
||||||
|
update.getAliases().stream().collect(Collectors.toList()),
|
||||||
|
new ArrayList<MonolingualTextValue>(),
|
||||||
|
update.getAddedStatements().stream().collect(Collectors.toList()),
|
||||||
|
update.getDeletedStatements().stream().collect(Collectors.toList()), summary);
|
||||||
|
}
|
||||||
|
} catch (MediaWikiApiErrorException e) {
|
||||||
|
// TODO find a way to report these errors to the user in a nice way
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
batchCursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of edits that remain to be done in the current batch
|
||||||
|
*/
|
||||||
|
public int remainingEdits() {
|
||||||
|
return scheduled.size() - (globalCursor + batchCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the progress, measured as a percentage
|
||||||
|
*/
|
||||||
|
public int progress() {
|
||||||
|
return (100 * (globalCursor + batchCursor)) / scheduled.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void prepareNewBatch()
|
||||||
|
throws InterruptedException {
|
||||||
|
// remove the previous batch from the remainingUpdates
|
||||||
|
globalCursor += currentBatch.size();
|
||||||
|
currentBatch.clear();
|
||||||
|
|
||||||
|
if (remainingUpdates.size() < batchSize) {
|
||||||
currentBatch = remainingUpdates;
|
currentBatch = remainingUpdates;
|
||||||
remainingUpdates = Collections.emptyList();
|
remainingUpdates = Collections.emptyList();
|
||||||
} else {
|
} else {
|
||||||
currentBatch = remainingUpdates.subList(0, batchSize);
|
currentBatch = remainingUpdates.subList(0, batchSize);
|
||||||
}
|
}
|
||||||
List<String> qidsToFetch = currentBatch.stream()
|
List<String> qidsToFetch = currentBatch.stream().filter(u -> !u.isNew()).map(u -> u.getItemId().getId())
|
||||||
.filter(u -> !u.isNew())
|
.collect(Collectors.toList());
|
||||||
.map(u -> u.getItemId().getId())
|
|
||||||
.collect(Collectors.toList());
|
// Get the current documents for this batch of updates
|
||||||
|
logger.info("Requesting documents");
|
||||||
// Get the current documents for this batch of updates
|
currentDocs = null;
|
||||||
logger.info("Requesting documents");
|
int retries = 3;
|
||||||
currentDocs = null;
|
while (currentDocs == null && retries > 0) {
|
||||||
int retries = 3;
|
try {
|
||||||
while (currentDocs == null && retries > 0) {
|
currentDocs = fetcher.getEntityDocuments(qidsToFetch);
|
||||||
try {
|
} catch (MediaWikiApiErrorException e) {
|
||||||
currentDocs = fetcher.getEntityDocuments(qidsToFetch);
|
e.printStackTrace();
|
||||||
} catch (MediaWikiApiErrorException e) {
|
Thread.sleep(5000);
|
||||||
e.printStackTrace();
|
}
|
||||||
Thread.sleep(5000);
|
retries--;
|
||||||
}
|
}
|
||||||
retries--;
|
if (currentDocs == null) {
|
||||||
}
|
throw new InterruptedException("Fetching current documents failed.");
|
||||||
if (currentDocs == null) {
|
}
|
||||||
throw new InterruptedException("Fetching current documents failed.");
|
batchCursor = 0;
|
||||||
}
|
}
|
||||||
batchCursor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,98 +1,120 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import com.google.refine.model.Project;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import com.google.refine.model.Cell;
|
import com.google.refine.model.Cell;
|
||||||
import com.google.refine.model.Column;
|
import com.google.refine.model.Column;
|
||||||
|
import com.google.refine.model.Project;
|
||||||
import com.google.refine.model.Recon;
|
import com.google.refine.model.Recon;
|
||||||
import com.google.refine.model.ReconCandidate;
|
import com.google.refine.model.ReconCandidate;
|
||||||
import com.google.refine.model.ReconStats;
|
import com.google.refine.model.ReconStats;
|
||||||
import com.google.refine.model.Row;
|
import com.google.refine.model.Row;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This keeps track of the new items that we
|
* This keeps track of the new items that we have created for each internal
|
||||||
* have created for each internal reconciliation id.
|
* reconciliation id.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class NewItemLibrary {
|
public class NewItemLibrary {
|
||||||
|
|
||||||
private Map<Long, String> map;
|
private Map<Long, String> map;
|
||||||
|
|
||||||
public NewItemLibrary() {
|
public NewItemLibrary() {
|
||||||
map = new HashMap<>();
|
map = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public NewItemLibrary(@JsonProperty("qidMap") Map<Long, String> map) {
|
public NewItemLibrary(@JsonProperty("qidMap") Map<Long, String> map) {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the Qid allocated to a given new cell
|
* Retrieves the Qid allocated to a given new cell
|
||||||
* @param id: the fake ItemId generated by the cell
|
*
|
||||||
|
* @param id:
|
||||||
|
* the fake ItemId generated by the cell
|
||||||
* @return the qid (or null if unallocated yet)
|
* @return the qid (or null if unallocated yet)
|
||||||
*/
|
*/
|
||||||
public String getQid(long id) {
|
public String getQid(long id) {
|
||||||
return map.get(id);
|
return map.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a Qid associated to a new cell
|
* Stores a Qid associated to a new cell
|
||||||
* @param id : the internal reconciliation id of the new cell
|
*
|
||||||
* @param qid : the associated Qid returned by Wikibase
|
* @param id
|
||||||
|
* : the internal reconciliation id of the new cell
|
||||||
|
* @param qid
|
||||||
|
* : the associated Qid returned by Wikibase
|
||||||
*/
|
*/
|
||||||
public void setQid(long id, String qid) {
|
public void setQid(long id, String qid) {
|
||||||
map.put(id, qid);
|
map.put(id, qid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the "new" reconciled cells to their allocated
|
* Changes the "new" reconciled cells to their allocated qids for later use.
|
||||||
* qids for later use.
|
|
||||||
*
|
*
|
||||||
* @param reset: set to true to revert the operation (set cells to "new")
|
* @param reset:
|
||||||
|
* set to true to revert the operation (set cells to "new")
|
||||||
*/
|
*/
|
||||||
public void updateReconciledCells(Project project, boolean reset) {
|
public void updateReconciledCells(Project project, boolean reset) {
|
||||||
|
|
||||||
Set<Integer> impactedColumns = new HashSet<>();
|
Set<Integer> impactedColumns = new HashSet<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that there is a slight violation of OpenRefine's model here:
|
* Note that there is a slight violation of OpenRefine's model here: if we
|
||||||
* if we reconcile multiple cells to the same new item, and then
|
* reconcile multiple cells to the same new item, and then perform this
|
||||||
* perform this operation on a subset of the corresponding rows,
|
* operation on a subset of the corresponding rows, we are going to modify cells
|
||||||
* we are going to modify cells that are outside the facet (because
|
* that are outside the facet (because they are reconciled to the same cell).
|
||||||
* they are reconciled to the same cell). But I think this is the
|
* But I think this is the right thing to do.
|
||||||
* right thing to do.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for(Row row : project.rows) {
|
for (Row row : project.rows) {
|
||||||
for(int i = 0; i != row.cells.size(); i++) {
|
for (int i = 0; i != row.cells.size(); i++) {
|
||||||
Cell cell = row.cells.get(i);
|
Cell cell = row.cells.get(i);
|
||||||
if (cell == null || cell.recon == null) {
|
if (cell == null || cell.recon == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Recon recon = cell.recon;
|
Recon recon = cell.recon;
|
||||||
if (Recon.Judgment.New.equals(recon.judgment) && !reset &&
|
if (Recon.Judgment.New.equals(recon.judgment) && !reset
|
||||||
map.containsKey(recon.judgmentHistoryEntry)) {
|
&& map.containsKey(recon.judgmentHistoryEntry)) {
|
||||||
recon.judgment = Recon.Judgment.Matched;
|
recon.judgment = Recon.Judgment.Matched;
|
||||||
recon.match = new ReconCandidate(
|
recon.match = new ReconCandidate(map.get(recon.judgmentHistoryEntry), cell.value.toString(),
|
||||||
map.get(recon.judgmentHistoryEntry),
|
new String[0], 100);
|
||||||
cell.value.toString(),
|
|
||||||
new String[0],
|
|
||||||
100);
|
|
||||||
impactedColumns.add(i);
|
impactedColumns.add(i);
|
||||||
} else if (Recon.Judgment.Matched.equals(recon.judgment) && reset &&
|
} else if (Recon.Judgment.Matched.equals(recon.judgment) && reset
|
||||||
map.containsKey(recon.judgmentHistoryEntry)) {
|
&& map.containsKey(recon.judgmentHistoryEntry)) {
|
||||||
recon.judgment = Recon.Judgment.New;
|
recon.judgment = Recon.Judgment.New;
|
||||||
recon.match = null;
|
recon.match = null;
|
||||||
impactedColumns.add(i);
|
impactedColumns.add(i);
|
||||||
@ -100,35 +122,36 @@ public class NewItemLibrary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update reconciliation statistics for impacted columns
|
// Update reconciliation statistics for impacted columns
|
||||||
for(Integer colId : impactedColumns) {
|
for (Integer colId : impactedColumns) {
|
||||||
Column column = project.columnModel.getColumnByCellIndex(colId);
|
Column column = project.columnModel.getColumnByCellIndex(colId);
|
||||||
column.setReconStats(ReconStats.create(project, colId));
|
column.setReconStats(ReconStats.create(project, colId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getter, only meant to be used by Jackson
|
* Getter, only meant to be used by Jackson
|
||||||
|
*
|
||||||
* @return the underlying map
|
* @return the underlying map
|
||||||
*/
|
*/
|
||||||
@JsonProperty("qidMap")
|
@JsonProperty("qidMap")
|
||||||
public Map<Long, String> getQidMap() {
|
public Map<Long, String> getQidMap() {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !NewItemLibrary.class.isInstance(other)) {
|
if (other == null || !NewItemLibrary.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
NewItemLibrary otherLibrary = (NewItemLibrary)other;
|
NewItemLibrary otherLibrary = (NewItemLibrary) other;
|
||||||
return map.equals(otherLibrary.getQidMap());
|
return map.equals(otherLibrary.getQidMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return map.hashCode();
|
return map.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return map.toString();
|
return map.toString();
|
||||||
|
@ -1,46 +1,64 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconEntityIdValue;
|
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
||||||
import org.wikidata.wdtk.datamodel.helpers.DatamodelConverter;
|
import org.wikidata.wdtk.datamodel.helpers.DatamodelConverter;
|
||||||
import org.wikidata.wdtk.datamodel.implementation.DataObjectFactoryImpl;
|
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.ItemIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue;
|
import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that rewrites an {@link ItemUpdate},
|
* A class that rewrites an {@link ItemUpdate}, replacing reconciled entity id
|
||||||
* replacing reconciled entity id values by their concrete
|
* values by their concrete values after creation of all the new items involved.
|
||||||
* values after creation of all the new items involved.
|
|
||||||
*
|
*
|
||||||
* If an item has not been created yet, an {@link IllegalArgumentException}
|
* If an item has not been created yet, an {@link IllegalArgumentException} will
|
||||||
* will be raised.
|
* be raised.
|
||||||
*
|
*
|
||||||
* The subject is treated as a special case: it is returned unchanged.
|
* The subject is treated as a special case: it is returned unchanged. This is
|
||||||
* This is because it is guaranteed not to appear in the update (but
|
* because it is guaranteed not to appear in the update (but it does appear in
|
||||||
* it does appear in the datamodel representation as the subject is passed around
|
* the datamodel representation as the subject is passed around to the Claim
|
||||||
* to the Claim objects its document contains).
|
* objects its document contains).
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ReconEntityRewriter extends DatamodelConverter {
|
public class ReconEntityRewriter extends DatamodelConverter {
|
||||||
|
|
||||||
private NewItemLibrary library;
|
private NewItemLibrary library;
|
||||||
private ItemIdValue subject;
|
private ItemIdValue subject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. Sets up a rewriter which uses the provided library
|
* Constructor. Sets up a rewriter which uses the provided library to look up
|
||||||
* to look up qids of new items, and the subject (which should not be
|
* qids of new items, and the subject (which should not be rewritten).
|
||||||
* rewritten).
|
|
||||||
*
|
*
|
||||||
* @param library
|
* @param library
|
||||||
* @param subject
|
* @param subject
|
||||||
@ -50,39 +68,35 @@ public class ReconEntityRewriter extends DatamodelConverter {
|
|||||||
this.library = library;
|
this.library = library;
|
||||||
this.subject = subject;
|
this.subject = subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemIdValue copy(ItemIdValue value) {
|
public ItemIdValue copy(ItemIdValue value) {
|
||||||
if(subject.equals(value)) {
|
if (subject.equals(value)) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
if(value instanceof ReconItemIdValue) {
|
if (value instanceof ReconItemIdValue) {
|
||||||
ReconItemIdValue recon = (ReconItemIdValue)value;
|
ReconItemIdValue recon = (ReconItemIdValue) value;
|
||||||
if(recon.isNew()) {
|
if (recon.isNew()) {
|
||||||
String newId = library.getQid(recon.getReconInternalId());
|
String newId = library.getQid(recon.getReconInternalId());
|
||||||
if(newId == null) {
|
if (newId == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Trying to rewrite an update where a new item was not created yet.");
|
"Trying to rewrite an update where a new item was not created yet.");
|
||||||
}
|
}
|
||||||
return Datamodel.makeItemIdValue(newId,
|
return Datamodel.makeItemIdValue(newId, recon.getRecon().identifierSpace);
|
||||||
recon.getRecon().identifierSpace);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.copy(value);
|
return super.copy(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemUpdate rewrite(ItemUpdate update) {
|
public ItemUpdate rewrite(ItemUpdate update) {
|
||||||
Set<MonolingualTextValue> labels = update.getLabels().stream()
|
Set<MonolingualTextValue> labels = update.getLabels().stream().map(l -> copy(l)).collect(Collectors.toSet());
|
||||||
.map(l -> copy(l)).collect(Collectors.toSet());
|
Set<MonolingualTextValue> descriptions = update.getDescriptions().stream().map(l -> copy(l))
|
||||||
Set<MonolingualTextValue> descriptions = update.getDescriptions().stream()
|
.collect(Collectors.toSet());
|
||||||
.map(l -> copy(l)).collect(Collectors.toSet());
|
Set<MonolingualTextValue> aliases = update.getAliases().stream().map(l -> copy(l)).collect(Collectors.toSet());
|
||||||
Set<MonolingualTextValue> aliases = update.getAliases().stream()
|
List<Statement> addedStatements = update.getAddedStatements().stream().map(l -> copy(l))
|
||||||
.map(l -> copy(l)).collect(Collectors.toSet());
|
.collect(Collectors.toList());
|
||||||
List<Statement> addedStatements = update.getAddedStatements().stream()
|
Set<Statement> deletedStatements = update.getDeletedStatements().stream().map(l -> copy(l))
|
||||||
.map(l -> copy(l)).collect(Collectors.toList());
|
.collect(Collectors.toSet());
|
||||||
Set<Statement> deletedStatements = update.getDeletedStatements().stream()
|
return new ItemUpdate(update.getItemId(), addedStatements, deletedStatements, labels, descriptions, aliases);
|
||||||
.map(l -> copy(l)).collect(Collectors.toSet());
|
|
||||||
return new ItemUpdate(update.getItemId(), addedStatements,
|
|
||||||
deletedStatements, labels, descriptions, aliases);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@ -9,37 +32,37 @@ import org.json.JSONWriter;
|
|||||||
import com.google.refine.Jsonizable;
|
import com.google.refine.Jsonizable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is just the necessary bits to store Wikidata credentials
|
* This is just the necessary bits to store Wikidata credentials in OpenRefine's
|
||||||
* in OpenRefine's preference store.
|
* preference store.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class WikibaseCredentials implements Jsonizable {
|
class WikibaseCredentials implements Jsonizable {
|
||||||
|
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
public WikibaseCredentials() {
|
public WikibaseCredentials() {
|
||||||
username = null;
|
username = null;
|
||||||
password = null;
|
password = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WikibaseCredentials(String username, String password) {
|
public WikibaseCredentials(String username, String password) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
return password;
|
return password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNonNull() {
|
public boolean isNonNull() {
|
||||||
return username != null && password != null && ! "null".equals(username) && ! "null".equals(password);
|
return username != null && password != null && !"null".equals(username) && !"null".equals(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,12 +77,10 @@ class WikibaseCredentials implements Jsonizable {
|
|||||||
writer.value(password);
|
writer.value(password);
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WikibaseCredentials load(JSONObject obj) throws JSONException {
|
|
||||||
return new WikibaseCredentials(
|
|
||||||
obj.getString("username"),
|
|
||||||
obj.getString("password"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public static WikibaseCredentials load(JSONObject obj)
|
||||||
|
throws JSONException {
|
||||||
|
return new WikibaseCredentials(obj.getString("username"), obj.getString("password"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.exporters;
|
package org.openrefine.wikidata.exporters;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -14,14 +37,12 @@ import org.wikidata.wdtk.datamodel.interfaces.TimeValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.ValueVisitor;
|
import org.wikidata.wdtk.datamodel.interfaces.ValueVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a Wikibase value as a string as required by QuickStatements.
|
* Prints a Wikibase value as a string as required by QuickStatements. Format
|
||||||
* Format documentation:
|
* documentation: https://www.wikidata.org/wiki/Help:QuickStatements
|
||||||
* https://www.wikidata.org/wiki/Help:QuickStatements
|
|
||||||
*
|
*
|
||||||
* Any new entity id will be
|
* Any new entity id will be assumed to be the last one created, represented
|
||||||
* assumed to be the last one created, represented with "LAST". It is
|
* with "LAST". It is fine to do this assumption because we are working on edit
|
||||||
* fine to do this assumption because we are working on edit batches
|
* batches previously scheduled by {@link QuickStatementsUpdateScheduler}.
|
||||||
* previously scheduled by {@link QuickStatementsUpdateScheduler}.
|
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
@ -37,7 +58,7 @@ public class QSValuePrinter implements ValueVisitor<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visit(EntityIdValue value) {
|
public String visit(EntityIdValue value) {
|
||||||
if (ReconEntityIdValue.class.isInstance(value) && ((ReconEntityIdValue)value).isNew()) {
|
if (ReconEntityIdValue.class.isInstance(value) && ((ReconEntityIdValue) value).isNew()) {
|
||||||
return "LAST";
|
return "LAST";
|
||||||
}
|
}
|
||||||
return value.getId();
|
return value.getId();
|
||||||
@ -45,19 +66,12 @@ public class QSValuePrinter implements ValueVisitor<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visit(GlobeCoordinatesValue value) {
|
public String visit(GlobeCoordinatesValue value) {
|
||||||
return String.format(
|
return String.format(Locale.US, "@%f/%f", value.getLatitude(), value.getLongitude());
|
||||||
Locale.US,
|
|
||||||
"@%f/%f",
|
|
||||||
value.getLatitude(),
|
|
||||||
value.getLongitude());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visit(MonolingualTextValue value) {
|
public String visit(MonolingualTextValue value) {
|
||||||
return String.format(
|
return String.format("%s:\"%s\"", value.getLanguageCode(), value.getText());
|
||||||
"%s:\"%s\"",
|
|
||||||
value.getLanguageCode(),
|
|
||||||
value.getText());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -66,22 +80,16 @@ public class QSValuePrinter implements ValueVisitor<String> {
|
|||||||
String unitIri = value.getUnit();
|
String unitIri = value.getUnit();
|
||||||
String unitRepresentation = "", boundsRepresentation = "";
|
String unitRepresentation = "", boundsRepresentation = "";
|
||||||
if (!unitIri.isEmpty()) {
|
if (!unitIri.isEmpty()) {
|
||||||
if (!unitIri.startsWith(unitPrefix))
|
if (!unitIri.startsWith(unitPrefix)) return null; // QuickStatements only accepts Qids as units
|
||||||
return null; // QuickStatements only accepts Qids as units
|
unitRepresentation = "U" + unitIri.substring(unitPrefix.length());
|
||||||
unitRepresentation = "U"+unitIri.substring(unitPrefix.length());
|
|
||||||
}
|
}
|
||||||
if (value.getLowerBound() != null) {
|
if (value.getLowerBound() != null) {
|
||||||
// bounds are always null at the same time so we know they are both not null
|
// bounds are always null at the same time so we know they are both not null
|
||||||
BigDecimal lowerBound = value.getLowerBound();
|
BigDecimal lowerBound = value.getLowerBound();
|
||||||
BigDecimal upperBound = value.getUpperBound();
|
BigDecimal upperBound = value.getUpperBound();
|
||||||
boundsRepresentation = String.format(Locale.US, "[%s,%s]",
|
boundsRepresentation = String.format(Locale.US, "[%s,%s]", lowerBound.toString(), upperBound.toString());
|
||||||
lowerBound.toString(), upperBound.toString());
|
|
||||||
}
|
}
|
||||||
return String.format(
|
return String.format(Locale.US, "%s%s%s", value.getNumericValue().toString(), boundsRepresentation,
|
||||||
Locale.US,
|
|
||||||
"%s%s%s",
|
|
||||||
value.getNumericValue().toString(),
|
|
||||||
boundsRepresentation,
|
|
||||||
unitRepresentation);
|
unitRepresentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +100,7 @@ public class QSValuePrinter implements ValueVisitor<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String visit(TimeValue value) {
|
public String visit(TimeValue value) {
|
||||||
return String.format(
|
return String.format("+%04d-%02d-%02dT%02d:%02d:%02dZ/%d", value.getYear(), value.getMonth(), value.getDay(),
|
||||||
"+%04d-%02d-%02dT%02d:%02d:%02dZ/%d",
|
value.getHour(), value.getMinute(), value.getSecond(), value.getPrecision());
|
||||||
value.getYear(),
|
|
||||||
value.getMonth(),
|
|
||||||
value.getDay(),
|
|
||||||
value.getHour(),
|
|
||||||
value.getMinute(),
|
|
||||||
value.getSecond(),
|
|
||||||
value.getPrecision());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.exporters;
|
package org.openrefine.wikidata.exporters;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -29,15 +52,13 @@ import org.wikidata.wdtk.datamodel.interfaces.ValueVisitor;
|
|||||||
public class QuickStatementsExporter implements WriterExporter {
|
public class QuickStatementsExporter implements WriterExporter {
|
||||||
|
|
||||||
final static Logger logger = LoggerFactory.getLogger("QuickStatementsExporter");
|
final static Logger logger = LoggerFactory.getLogger("QuickStatementsExporter");
|
||||||
|
|
||||||
public static final String impossibleSchedulingErrorMessage =
|
|
||||||
"This edit batch cannot be performed with QuickStatements due to the structure of its new items.";
|
|
||||||
public static final String noSchemaErrorMessage =
|
|
||||||
"No schema was provided. You need to align your project with Wikidata first.";
|
|
||||||
|
|
||||||
public QuickStatementsExporter(){
|
public static final String impossibleSchedulingErrorMessage = "This edit batch cannot be performed with QuickStatements due to the structure of its new items.";
|
||||||
|
public static final String noSchemaErrorMessage = "No schema was provided. You need to align your project with Wikidata first.";
|
||||||
|
|
||||||
|
public QuickStatementsExporter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getContentType() {
|
public String getContentType() {
|
||||||
return "text/plain";
|
return "text/plain";
|
||||||
@ -53,41 +74,45 @@ public class QuickStatementsExporter implements WriterExporter {
|
|||||||
translateSchema(project, engine, schema, writer);
|
translateSchema(project, engine, schema, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports a project and a schema to a QuickStatements file
|
* Exports a project and a schema to a QuickStatements file
|
||||||
*
|
*
|
||||||
* @param project
|
* @param project
|
||||||
* the project to translate
|
* the project to translate
|
||||||
* @param engine
|
* @param engine
|
||||||
* the engine used for evaluation of the edits
|
* the engine used for evaluation of the edits
|
||||||
* @param schema
|
* @param schema
|
||||||
* the WikibaseSchema used for translation of tabular data to edits
|
* the WikibaseSchema used for translation of tabular data to edits
|
||||||
* @param writer
|
* @param writer
|
||||||
* the writer to which the QS should be written
|
* the writer to which the QS should be written
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void translateSchema(Project project, Engine engine, WikibaseSchema schema, Writer writer) throws IOException {
|
public void translateSchema(Project project, Engine engine, WikibaseSchema schema, Writer writer)
|
||||||
|
throws IOException {
|
||||||
List<ItemUpdate> items = schema.evaluate(project, engine);
|
List<ItemUpdate> items = schema.evaluate(project, engine);
|
||||||
translateItemList(items, writer);
|
translateItemList(items, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void translateItemList(List<ItemUpdate> updates, Writer writer) throws IOException {
|
public void translateItemList(List<ItemUpdate> updates, Writer writer)
|
||||||
|
throws IOException {
|
||||||
QuickStatementsUpdateScheduler scheduler = new QuickStatementsUpdateScheduler();
|
QuickStatementsUpdateScheduler scheduler = new QuickStatementsUpdateScheduler();
|
||||||
try {
|
try {
|
||||||
List<ItemUpdate> scheduled = scheduler.schedule(updates);
|
List<ItemUpdate> scheduled = scheduler.schedule(updates);
|
||||||
for (ItemUpdate item : scheduled) {
|
for (ItemUpdate item : scheduled) {
|
||||||
translateItem(item, writer);
|
translateItem(item, writer);
|
||||||
}
|
}
|
||||||
} catch(ImpossibleSchedulingException e) {
|
} catch (ImpossibleSchedulingException e) {
|
||||||
writer.write(impossibleSchedulingErrorMessage);
|
writer.write(impossibleSchedulingErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void translateNameDescr(String qid, Set<MonolingualTextValue> values, String prefix, ItemIdValue id, Writer writer) throws IOException {
|
protected void translateNameDescr(String qid, Set<MonolingualTextValue> values, String prefix, ItemIdValue id,
|
||||||
|
Writer writer)
|
||||||
|
throws IOException {
|
||||||
for (MonolingualTextValue value : values) {
|
for (MonolingualTextValue value : values) {
|
||||||
writer.write(qid+"\t");
|
writer.write(qid + "\t");
|
||||||
writer.write(prefix);
|
writer.write(prefix);
|
||||||
writer.write(value.getLanguageCode());
|
writer.write(value.getLanguageCode());
|
||||||
writer.write("\t\"");
|
writer.write("\t\"");
|
||||||
@ -95,19 +120,20 @@ public class QuickStatementsExporter implements WriterExporter {
|
|||||||
writer.write("\"\n");
|
writer.write("\"\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void translateItem(ItemUpdate item, Writer writer) throws IOException {
|
protected void translateItem(ItemUpdate item, Writer writer)
|
||||||
|
throws IOException {
|
||||||
String qid = item.getItemId().getId();
|
String qid = item.getItemId().getId();
|
||||||
if (item.isNew()) {
|
if (item.isNew()) {
|
||||||
writer.write("CREATE\n");
|
writer.write("CREATE\n");
|
||||||
qid = "LAST";
|
qid = "LAST";
|
||||||
item = item.normalizeLabelsAndAliases();
|
item = item.normalizeLabelsAndAliases();
|
||||||
}
|
}
|
||||||
|
|
||||||
translateNameDescr(qid, item.getLabels(), "L", item.getItemId(), writer);
|
translateNameDescr(qid, item.getLabels(), "L", item.getItemId(), writer);
|
||||||
translateNameDescr(qid, item.getDescriptions(), "D", item.getItemId(), writer);
|
translateNameDescr(qid, item.getDescriptions(), "D", item.getItemId(), writer);
|
||||||
translateNameDescr(qid, item.getAliases(), "A", item.getItemId(), writer);
|
translateNameDescr(qid, item.getAliases(), "A", item.getItemId(), writer);
|
||||||
|
|
||||||
for (Statement s : item.getAddedStatements()) {
|
for (Statement s : item.getAddedStatements()) {
|
||||||
translateStatement(qid, s, s.getClaim().getMainSnak().getPropertyId().getId(), true, writer);
|
translateStatement(qid, s, s.getClaim().getMainSnak().getPropertyId().getId(), true, writer);
|
||||||
}
|
}
|
||||||
@ -115,38 +141,41 @@ public class QuickStatementsExporter implements WriterExporter {
|
|||||||
translateStatement(qid, s, s.getClaim().getMainSnak().getPropertyId().getId(), false, writer);
|
translateStatement(qid, s, s.getClaim().getMainSnak().getPropertyId().getId(), false, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void translateStatement(String qid, Statement statement, String pid, boolean add, Writer writer) throws IOException {
|
protected void translateStatement(String qid, Statement statement, String pid, boolean add, Writer writer)
|
||||||
|
throws IOException {
|
||||||
Claim claim = statement.getClaim();
|
Claim claim = statement.getClaim();
|
||||||
|
|
||||||
Value val = claim.getValue();
|
Value val = claim.getValue();
|
||||||
ValueVisitor<String> vv = new QSValuePrinter();
|
ValueVisitor<String> vv = new QSValuePrinter();
|
||||||
String targetValue = val.accept(vv);
|
String targetValue = val.accept(vv);
|
||||||
if (targetValue != null) {
|
if (targetValue != null) {
|
||||||
if (! add) {
|
if (!add) {
|
||||||
writer.write("- ");
|
writer.write("- ");
|
||||||
}
|
}
|
||||||
writer.write(qid + "\t" + pid + "\t" + targetValue);
|
writer.write(qid + "\t" + pid + "\t" + targetValue);
|
||||||
for(SnakGroup q : claim.getQualifiers()) {
|
for (SnakGroup q : claim.getQualifiers()) {
|
||||||
translateSnakGroup(q, false, writer);
|
translateSnakGroup(q, false, writer);
|
||||||
}
|
}
|
||||||
for(Reference r : statement.getReferences()) {
|
for (Reference r : statement.getReferences()) {
|
||||||
for(SnakGroup g : r.getSnakGroups()) {
|
for (SnakGroup g : r.getSnakGroups()) {
|
||||||
translateSnakGroup(g, true, writer);
|
translateSnakGroup(g, true, writer);
|
||||||
}
|
}
|
||||||
break; // QS only supports one reference
|
break; // QS only supports one reference
|
||||||
}
|
}
|
||||||
writer.write("\n");
|
writer.write("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void translateSnakGroup(SnakGroup sg, boolean reference, Writer writer) throws IOException {
|
protected void translateSnakGroup(SnakGroup sg, boolean reference, Writer writer)
|
||||||
for(Snak s : sg.getSnaks()) {
|
throws IOException {
|
||||||
|
for (Snak s : sg.getSnaks()) {
|
||||||
translateSnak(s, reference, writer);
|
translateSnak(s, reference, writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void translateSnak(Snak s, boolean reference, Writer writer) throws IOException {
|
protected void translateSnak(Snak s, boolean reference, Writer writer)
|
||||||
|
throws IOException {
|
||||||
String pid = s.getPropertyId().getId();
|
String pid = s.getPropertyId().getId();
|
||||||
if (reference) {
|
if (reference) {
|
||||||
pid = pid.replace('P', 'S');
|
pid = pid.replace('P', 'S');
|
||||||
@ -154,10 +183,9 @@ public class QuickStatementsExporter implements WriterExporter {
|
|||||||
Value val = s.getValue();
|
Value val = s.getValue();
|
||||||
ValueVisitor<String> vv = new QSValuePrinter();
|
ValueVisitor<String> vv = new QSValuePrinter();
|
||||||
String valStr = val.accept(vv);
|
String valStr = val.accept(vv);
|
||||||
if(valStr != null) {
|
if (valStr != null) {
|
||||||
writer.write("\t" + pid + "\t" + valStr);
|
writer.write("\t" + pid + "\t" + valStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,48 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.operations;
|
package org.openrefine.wikidata.operations;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.LineNumberReader;
|
import java.io.LineNumberReader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
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 org.openrefine.wikidata.editing.ConnectionManager;
|
import org.openrefine.wikidata.editing.ConnectionManager;
|
||||||
import org.openrefine.wikidata.editing.EditBatchProcessor;
|
import org.openrefine.wikidata.editing.EditBatchProcessor;
|
||||||
import org.openrefine.wikidata.editing.NewItemLibrary;
|
import org.openrefine.wikidata.editing.NewItemLibrary;
|
||||||
import org.openrefine.wikidata.editing.ReconEntityRewriter;
|
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
|
||||||
import org.openrefine.wikidata.updates.scheduler.ImpossibleSchedulingException;
|
|
||||||
import org.openrefine.wikidata.updates.scheduler.UpdateScheduler;
|
|
||||||
import org.openrefine.wikidata.updates.scheduler.WikibaseAPIUpdateScheduler;
|
|
||||||
import org.openrefine.wikidata.schema.WikibaseSchema;
|
import org.openrefine.wikidata.schema.WikibaseSchema;
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconEntityIdValue;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.wikidata.wdtk.datamodel.implementation.DataObjectFactoryImpl;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.DataObjectFactory;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityDocument;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemDocument;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue;
|
|
||||||
import org.wikidata.wdtk.util.WebResourceFetcherImpl;
|
import org.wikidata.wdtk.util.WebResourceFetcherImpl;
|
||||||
import org.wikidata.wdtk.wikibaseapi.ApiConnection;
|
import org.wikidata.wdtk.wikibaseapi.ApiConnection;
|
||||||
import org.wikidata.wdtk.wikibaseapi.TermStatementUpdate;
|
|
||||||
import org.wikidata.wdtk.wikibaseapi.WikibaseDataEditor;
|
import org.wikidata.wdtk.wikibaseapi.WikibaseDataEditor;
|
||||||
import org.wikidata.wdtk.wikibaseapi.WikibaseDataFetcher;
|
import org.wikidata.wdtk.wikibaseapi.WikibaseDataFetcher;
|
||||||
import org.wikidata.wdtk.wikibaseapi.apierrors.MediaWikiApiErrorException;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.SiteLink;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
@ -53,22 +57,19 @@ import com.google.refine.process.LongRunningProcess;
|
|||||||
import com.google.refine.process.Process;
|
import com.google.refine.process.Process;
|
||||||
import com.google.refine.util.Pool;
|
import com.google.refine.util.Pool;
|
||||||
|
|
||||||
|
|
||||||
public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
||||||
static final Logger logger = LoggerFactory
|
|
||||||
.getLogger(PerformWikibaseEditsOperation.class);
|
static final Logger logger = LoggerFactory.getLogger(PerformWikibaseEditsOperation.class);
|
||||||
|
|
||||||
private String summary;
|
private String summary;
|
||||||
|
|
||||||
public PerformWikibaseEditsOperation(
|
public PerformWikibaseEditsOperation(JSONObject engineConfig, String summary) {
|
||||||
JSONObject engineConfig,
|
|
||||||
String summary) {
|
|
||||||
super(engineConfig);
|
super(engineConfig);
|
||||||
this.summary = summary;
|
this.summary = summary;
|
||||||
|
|
||||||
// getEngine(request, project);
|
// getEngine(request, project);
|
||||||
}
|
}
|
||||||
|
|
||||||
static public AbstractOperation reconstruct(Project project, JSONObject obj)
|
static public AbstractOperation reconstruct(Project project, JSONObject obj)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
JSONObject engineConfig = obj.getJSONObject("engineConfig");
|
JSONObject engineConfig = obj.getJSONObject("engineConfig");
|
||||||
@ -76,12 +77,9 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
if (obj.has("summary")) {
|
if (obj.has("summary")) {
|
||||||
summary = obj.getString("summary");
|
summary = obj.getString("summary");
|
||||||
}
|
}
|
||||||
return new PerformWikibaseEditsOperation(
|
return new PerformWikibaseEditsOperation(engineConfig, summary);
|
||||||
engineConfig,
|
|
||||||
summary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(JSONWriter writer, Properties options)
|
public void write(JSONWriter writer, Properties options)
|
||||||
throws JSONException {
|
throws JSONException {
|
||||||
@ -96,26 +94,22 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
writer.value(getEngineConfig());
|
writer.value(getEngineConfig());
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getBriefDescription(Project project) {
|
protected String getBriefDescription(Project project) {
|
||||||
return "Peform edits on Wikidata";
|
return "Peform edits on Wikidata";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Process createProcess(Project project, Properties options) throws Exception {
|
public Process createProcess(Project project, Properties options)
|
||||||
return new PerformEditsProcess(
|
throws Exception {
|
||||||
project,
|
return new PerformEditsProcess(project, createEngine(project), getBriefDescription(project), summary);
|
||||||
createEngine(project),
|
|
||||||
getBriefDescription(project),
|
|
||||||
summary
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public class PerformWikibaseEditsChange implements Change {
|
static public class PerformWikibaseEditsChange implements Change {
|
||||||
|
|
||||||
private NewItemLibrary newItemLibrary;
|
private NewItemLibrary newItemLibrary;
|
||||||
|
|
||||||
public PerformWikibaseEditsChange(NewItemLibrary library) {
|
public PerformWikibaseEditsChange(NewItemLibrary library) {
|
||||||
newItemLibrary = library;
|
newItemLibrary = library;
|
||||||
}
|
}
|
||||||
@ -128,7 +122,7 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void revert(Project project) {
|
public void revert(Project project) {
|
||||||
// this does not do anything on Wikibase side -
|
// this does not do anything on Wikibase side -
|
||||||
// (we don't revert changes on Wikidata either)
|
// (we don't revert changes on Wikidata either)
|
||||||
newItemLibrary.updateReconciledCells(project, true);
|
newItemLibrary.updateReconciledCells(project, true);
|
||||||
}
|
}
|
||||||
@ -139,11 +133,11 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
if (newItemLibrary != null) {
|
if (newItemLibrary != null) {
|
||||||
writer.write("newItems=");
|
writer.write("newItems=");
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
writer.write(mapper.writeValueAsString(newItemLibrary)+"\n");
|
writer.write(mapper.writeValueAsString(newItemLibrary) + "\n");
|
||||||
}
|
}
|
||||||
writer.write("/ec/\n"); // end of change
|
writer.write("/ec/\n"); // end of change
|
||||||
}
|
}
|
||||||
|
|
||||||
static public Change load(LineNumberReader reader, Pool pool)
|
static public Change load(LineNumberReader reader, Pool pool)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
NewItemLibrary library = new NewItemLibrary();
|
NewItemLibrary library = new NewItemLibrary();
|
||||||
@ -152,7 +146,7 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
int equal = line.indexOf('=');
|
int equal = line.indexOf('=');
|
||||||
CharSequence field = line.subSequence(0, equal);
|
CharSequence field = line.subSequence(0, equal);
|
||||||
String value = line.substring(equal + 1);
|
String value = line.substring(equal + 1);
|
||||||
|
|
||||||
if ("newItems".equals(field)) {
|
if ("newItems".equals(field)) {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
library = mapper.readValue(value, NewItemLibrary.class);
|
library = mapper.readValue(value, NewItemLibrary.class);
|
||||||
@ -160,19 +154,18 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
}
|
}
|
||||||
return new PerformWikibaseEditsChange(library);
|
return new PerformWikibaseEditsChange(library);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PerformEditsProcess extends LongRunningProcess implements Runnable {
|
public class PerformEditsProcess extends LongRunningProcess implements Runnable {
|
||||||
|
|
||||||
protected Project _project;
|
protected Project _project;
|
||||||
protected Engine _engine;
|
protected Engine _engine;
|
||||||
protected WikibaseSchema _schema;
|
protected WikibaseSchema _schema;
|
||||||
protected String _summary;
|
protected String _summary;
|
||||||
protected final long _historyEntryID;
|
protected final long _historyEntryID;
|
||||||
|
|
||||||
protected PerformEditsProcess(Project project,
|
protected PerformEditsProcess(Project project, Engine engine, String description, String summary) {
|
||||||
Engine engine, String description, String summary) {
|
|
||||||
super(description);
|
super(description);
|
||||||
this._project = project;
|
this._project = project;
|
||||||
this._engine = engine;
|
this._engine = engine;
|
||||||
@ -183,7 +176,7 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
WebResourceFetcherImpl.setUserAgent("OpenRefine Wikidata extension");
|
WebResourceFetcherImpl.setUserAgent("OpenRefine Wikidata extension");
|
||||||
ConnectionManager manager = ConnectionManager.getInstance();
|
ConnectionManager manager = ConnectionManager.getInstance();
|
||||||
if (!manager.isLoggedIn()) {
|
if (!manager.isLoggedIn()) {
|
||||||
@ -193,21 +186,21 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
|
|
||||||
WikibaseDataFetcher wbdf = new WikibaseDataFetcher(connection, _schema.getBaseIri());
|
WikibaseDataFetcher wbdf = new WikibaseDataFetcher(connection, _schema.getBaseIri());
|
||||||
WikibaseDataEditor wbde = new WikibaseDataEditor(connection, _schema.getBaseIri());
|
WikibaseDataEditor wbde = new WikibaseDataEditor(connection, _schema.getBaseIri());
|
||||||
|
|
||||||
// Evaluate the schema
|
// Evaluate the schema
|
||||||
List<ItemUpdate> itemDocuments = _schema.evaluate(_project, _engine);
|
List<ItemUpdate> itemDocuments = _schema.evaluate(_project, _engine);
|
||||||
|
|
||||||
// Prepare the edits
|
// Prepare the edits
|
||||||
NewItemLibrary newItemLibrary = new NewItemLibrary();
|
NewItemLibrary newItemLibrary = new NewItemLibrary();
|
||||||
EditBatchProcessor processor = new EditBatchProcessor(wbdf,
|
EditBatchProcessor processor = new EditBatchProcessor(wbdf, wbde, itemDocuments, newItemLibrary, _summary,
|
||||||
wbde, itemDocuments, newItemLibrary, _summary, 50);
|
50);
|
||||||
|
|
||||||
// Perform edits
|
// Perform edits
|
||||||
logger.info("Performing edits");
|
logger.info("Performing edits");
|
||||||
while(processor.remainingEdits() > 0) {
|
while (processor.remainingEdits() > 0) {
|
||||||
try {
|
try {
|
||||||
processor.performEdit();
|
processor.performEdit();
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
_canceled = true;
|
_canceled = true;
|
||||||
}
|
}
|
||||||
_progress = processor.progress();
|
_progress = processor.progress();
|
||||||
@ -215,20 +208,15 @@ public class PerformWikibaseEditsOperation extends EngineDependentOperation {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_progress = 100;
|
_progress = 100;
|
||||||
|
|
||||||
if (!_canceled) {
|
if (!_canceled) {
|
||||||
Change change = new PerformWikibaseEditsChange(newItemLibrary);
|
Change change = new PerformWikibaseEditsChange(newItemLibrary);
|
||||||
|
|
||||||
HistoryEntry historyEntry = new HistoryEntry(
|
HistoryEntry historyEntry = new HistoryEntry(_historyEntryID, _project, _description,
|
||||||
_historyEntryID,
|
PerformWikibaseEditsOperation.this, change);
|
||||||
_project,
|
|
||||||
_description,
|
|
||||||
PerformWikibaseEditsOperation.this,
|
|
||||||
change
|
|
||||||
);
|
|
||||||
|
|
||||||
_project.history.addEntry(historyEntry);
|
_project.history.addEntry(historyEntry);
|
||||||
_project.processManager.onDoneProcess(this);
|
_project.processManager.onDoneProcess(this);
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,38 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.operations;
|
package org.openrefine.wikidata.operations;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.LineNumberReader;
|
import java.io.LineNumberReader;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
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 org.openrefine.wikidata.schema.WbItemConstant;
|
|
||||||
import org.openrefine.wikidata.schema.WbItemDocumentExpr;
|
|
||||||
import org.openrefine.wikidata.schema.WbNameDescExpr;
|
|
||||||
import org.openrefine.wikidata.schema.WbStatementGroupExpr;
|
|
||||||
import org.openrefine.wikidata.schema.WikibaseSchema;
|
import org.openrefine.wikidata.schema.WikibaseSchema;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import com.google.refine.history.Change;
|
import com.google.refine.history.Change;
|
||||||
import com.google.refine.history.HistoryEntry;
|
import com.google.refine.history.HistoryEntry;
|
||||||
import com.google.refine.model.AbstractOperation;
|
import com.google.refine.model.AbstractOperation;
|
||||||
@ -33,14 +47,12 @@ public class SaveWikibaseSchemaOperation extends AbstractOperation {
|
|||||||
|
|
||||||
public SaveWikibaseSchemaOperation(WikibaseSchema schema) {
|
public SaveWikibaseSchemaOperation(WikibaseSchema schema) {
|
||||||
this._schema = schema;
|
this._schema = schema;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public AbstractOperation reconstruct(Project project, JSONObject obj)
|
static public AbstractOperation reconstruct(Project project, JSONObject obj)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
return new SaveWikibaseSchemaOperation(WikibaseSchema.reconstruct(obj
|
return new SaveWikibaseSchemaOperation(WikibaseSchema.reconstruct(obj.getJSONObject("schema")));
|
||||||
.getJSONObject("schema")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(JSONWriter writer, Properties options)
|
public void write(JSONWriter writer, Properties options)
|
||||||
@ -62,32 +74,32 @@ public class SaveWikibaseSchemaOperation extends AbstractOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HistoryEntry createHistoryEntry(Project project,
|
protected HistoryEntry createHistoryEntry(Project project, long historyEntryID)
|
||||||
long historyEntryID) throws Exception {
|
throws Exception {
|
||||||
String description = "Save Wikibase schema skeleton";
|
String description = "Save Wikibase schema skeleton";
|
||||||
|
|
||||||
Change change = new WikibaseSchemaChange(_schema);
|
Change change = new WikibaseSchemaChange(_schema);
|
||||||
|
|
||||||
return new HistoryEntry(historyEntryID, project, description,
|
return new HistoryEntry(historyEntryID, project, description, SaveWikibaseSchemaOperation.this, change);
|
||||||
SaveWikibaseSchemaOperation.this, change);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public class WikibaseSchemaChange implements Change {
|
static public class WikibaseSchemaChange implements Change {
|
||||||
|
|
||||||
final protected WikibaseSchema _newSchema;
|
final protected WikibaseSchema _newSchema;
|
||||||
protected WikibaseSchema _oldSchema = null;
|
protected WikibaseSchema _oldSchema = null;
|
||||||
public final static String overlayModelKey = "wikibaseSchema";
|
public final static String overlayModelKey = "wikibaseSchema";
|
||||||
|
|
||||||
public WikibaseSchemaChange(WikibaseSchema newSchema) {
|
public WikibaseSchemaChange(WikibaseSchema newSchema) {
|
||||||
_newSchema = newSchema;
|
_newSchema = newSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply(Project project) {
|
public void apply(Project project) {
|
||||||
synchronized (project) {
|
synchronized (project) {
|
||||||
_oldSchema = (WikibaseSchema) project.overlayModels.get(overlayModelKey);
|
_oldSchema = (WikibaseSchema) project.overlayModels.get(overlayModelKey);
|
||||||
project.overlayModels.put(overlayModelKey, _newSchema);
|
project.overlayModels.put(overlayModelKey, _newSchema);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void revert(Project project) {
|
public void revert(Project project) {
|
||||||
synchronized (project) {
|
synchronized (project) {
|
||||||
if (_oldSchema == null) {
|
if (_oldSchema == null) {
|
||||||
@ -97,8 +109,9 @@ public class SaveWikibaseSchemaOperation extends AbstractOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(Writer writer, Properties options) throws IOException {
|
public void save(Writer writer, Properties options)
|
||||||
|
throws IOException {
|
||||||
writer.write("newSchema=");
|
writer.write("newSchema=");
|
||||||
writeWikibaseSchema(_newSchema, writer);
|
writeWikibaseSchema(_newSchema, writer);
|
||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
@ -107,33 +120,31 @@ public class SaveWikibaseSchemaOperation extends AbstractOperation {
|
|||||||
writer.write('\n');
|
writer.write('\n');
|
||||||
writer.write("/ec/\n"); // end of change marker
|
writer.write("/ec/\n"); // end of change marker
|
||||||
}
|
}
|
||||||
|
|
||||||
static public Change load(LineNumberReader reader, Pool pool)
|
static public Change load(LineNumberReader reader, Pool pool)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
WikibaseSchema oldSchema = null;
|
WikibaseSchema oldSchema = null;
|
||||||
WikibaseSchema newSchema = null;
|
WikibaseSchema newSchema = null;
|
||||||
|
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null && !"/ec/".equals(line)) {
|
while ((line = reader.readLine()) != null && !"/ec/".equals(line)) {
|
||||||
int equal = line.indexOf('=');
|
int equal = line.indexOf('=');
|
||||||
CharSequence field = line.subSequence(0, equal);
|
CharSequence field = line.subSequence(0, equal);
|
||||||
String value = line.substring(equal + 1);
|
String value = line.substring(equal + 1);
|
||||||
|
|
||||||
if ("oldSchema".equals(field) && value.length() > 0) {
|
if ("oldSchema".equals(field) && value.length() > 0) {
|
||||||
oldSchema = WikibaseSchema.reconstruct(ParsingUtilities
|
oldSchema = WikibaseSchema.reconstruct(ParsingUtilities.evaluateJsonStringToObject(value));
|
||||||
.evaluateJsonStringToObject(value));
|
|
||||||
} else if ("newSchema".equals(field) && value.length() > 0) {
|
} else if ("newSchema".equals(field) && value.length() > 0) {
|
||||||
newSchema = WikibaseSchema.reconstruct(ParsingUtilities
|
newSchema = WikibaseSchema.reconstruct(ParsingUtilities.evaluateJsonStringToObject(value));
|
||||||
.evaluateJsonStringToObject(value));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WikibaseSchemaChange change = new WikibaseSchemaChange(newSchema);
|
WikibaseSchemaChange change = new WikibaseSchemaChange(newSchema);
|
||||||
change._oldSchema = oldSchema;
|
change._oldSchema = oldSchema;
|
||||||
|
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
static protected void writeWikibaseSchema(WikibaseSchema s, Writer writer)
|
static protected void writeWikibaseSchema(WikibaseSchema s, Writer writer)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
|
@ -1,4 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -14,16 +36,20 @@ import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
|||||||
public interface ConstraintFetcher {
|
public interface ConstraintFetcher {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the regular expression for formatting a property, or null if
|
* Retrieves the regular expression for formatting a property, or null if there
|
||||||
* there is no such constraint
|
* is no such constraint
|
||||||
|
*
|
||||||
* @param pid
|
* @param pid
|
||||||
* @return the expression of a regular expression which should be compatible with java.util.regex
|
* @return the expression of a regular expression which should be compatible
|
||||||
|
* with java.util.regex
|
||||||
*/
|
*/
|
||||||
String getFormatRegex(PropertyIdValue pid);
|
String getFormatRegex(PropertyIdValue pid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the property that is the inverse of a given property
|
* Retrieves the property that is the inverse of a given property
|
||||||
* @param pid: the property to retrieve the inverse for
|
*
|
||||||
|
* @param pid:
|
||||||
|
* the property to retrieve the inverse for
|
||||||
* @return the pid of the inverse property
|
* @return the pid of the inverse property
|
||||||
*/
|
*/
|
||||||
PropertyIdValue getInversePid(PropertyIdValue pid);
|
PropertyIdValue getInversePid(PropertyIdValue pid);
|
||||||
@ -44,12 +70,14 @@ public interface ConstraintFetcher {
|
|||||||
boolean isForReferencesOnly(PropertyIdValue pid);
|
boolean isForReferencesOnly(PropertyIdValue pid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of allowed qualifiers (as property ids) for this property (null if any)
|
* Get the list of allowed qualifiers (as property ids) for this property (null
|
||||||
|
* if any)
|
||||||
*/
|
*/
|
||||||
Set<PropertyIdValue> allowedQualifiers(PropertyIdValue pid);
|
Set<PropertyIdValue> allowedQualifiers(PropertyIdValue pid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the list of mandatory qualifiers (as property ids) for this property (null if any)
|
* Get the list of mandatory qualifiers (as property ids) for this property
|
||||||
|
* (null if any)
|
||||||
*/
|
*/
|
||||||
Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue pid);
|
Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue pid);
|
||||||
|
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -18,8 +41,6 @@ import org.openrefine.wikidata.qa.scrutinizers.SingleValueScrutinizer;
|
|||||||
import org.openrefine.wikidata.qa.scrutinizers.UnsourcedScrutinizer;
|
import org.openrefine.wikidata.qa.scrutinizers.UnsourcedScrutinizer;
|
||||||
import org.openrefine.wikidata.qa.scrutinizers.WhitespaceScrutinizer;
|
import org.openrefine.wikidata.qa.scrutinizers.WhitespaceScrutinizer;
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
import org.openrefine.wikidata.updates.scheduler.ImpossibleSchedulingException;
|
|
||||||
import org.openrefine.wikidata.updates.scheduler.UpdateScheduler;
|
|
||||||
import org.openrefine.wikidata.updates.scheduler.WikibaseAPIUpdateScheduler;
|
import org.openrefine.wikidata.updates.scheduler.WikibaseAPIUpdateScheduler;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
||||||
|
|
||||||
@ -30,15 +51,16 @@ import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class EditInspector {
|
public class EditInspector {
|
||||||
|
|
||||||
private Map<String, EditScrutinizer> scrutinizers;
|
private Map<String, EditScrutinizer> scrutinizers;
|
||||||
private QAWarningStore warningStore;
|
private QAWarningStore warningStore;
|
||||||
private ConstraintFetcher fetcher;
|
private ConstraintFetcher fetcher;
|
||||||
|
|
||||||
public EditInspector(QAWarningStore warningStore) {
|
public EditInspector(QAWarningStore warningStore) {
|
||||||
this.scrutinizers = new HashMap<>();
|
this.scrutinizers = new HashMap<>();
|
||||||
this.fetcher = new WikidataConstraintFetcher();
|
this.fetcher = new WikidataConstraintFetcher();
|
||||||
this.warningStore = warningStore;
|
this.warningStore = warningStore;
|
||||||
|
|
||||||
// Register all known scrutinizers here
|
// Register all known scrutinizers here
|
||||||
register(new NewItemScrutinizer());
|
register(new NewItemScrutinizer());
|
||||||
register(new FormatScrutinizer());
|
register(new FormatScrutinizer());
|
||||||
@ -52,9 +74,10 @@ public class EditInspector {
|
|||||||
register(new NoEditsMadeScrutinizer());
|
register(new NoEditsMadeScrutinizer());
|
||||||
register(new WhitespaceScrutinizer());
|
register(new WhitespaceScrutinizer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new scrutinizer to the inspector
|
* Adds a new scrutinizer to the inspector
|
||||||
|
*
|
||||||
* @param scrutinizer
|
* @param scrutinizer
|
||||||
*/
|
*/
|
||||||
public void register(EditScrutinizer scrutinizer) {
|
public void register(EditScrutinizer scrutinizer) {
|
||||||
@ -63,11 +86,11 @@ public class EditInspector {
|
|||||||
scrutinizer.setStore(warningStore);
|
scrutinizer.setStore(warningStore);
|
||||||
scrutinizer.setFetcher(fetcher);
|
scrutinizer.setFetcher(fetcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inspect a batch of edits with the registered scrutinizers
|
* Inspect a batch of edits with the registered scrutinizers
|
||||||
* @param editBatch
|
*
|
||||||
|
* @param editBatch
|
||||||
*/
|
*/
|
||||||
public void inspect(List<ItemUpdate> editBatch) {
|
public void inspect(List<ItemUpdate> editBatch) {
|
||||||
// First, schedule them with some scheduler,
|
// First, schedule them with some scheduler,
|
||||||
@ -75,16 +98,14 @@ public class EditInspector {
|
|||||||
WikibaseAPIUpdateScheduler scheduler = new WikibaseAPIUpdateScheduler();
|
WikibaseAPIUpdateScheduler scheduler = new WikibaseAPIUpdateScheduler();
|
||||||
editBatch = scheduler.schedule(editBatch);
|
editBatch = scheduler.schedule(editBatch);
|
||||||
|
|
||||||
Map<EntityIdValue, ItemUpdate> updates = ItemUpdate.groupBySubject(editBatch);
|
Map<EntityIdValue, ItemUpdate> updates = ItemUpdate.groupBySubject(editBatch);
|
||||||
List<ItemUpdate> mergedUpdates = updates.values().stream().collect(Collectors.toList());
|
List<ItemUpdate> mergedUpdates = updates.values().stream().collect(Collectors.toList());
|
||||||
for(EditScrutinizer scrutinizer : scrutinizers.values()) {
|
for (EditScrutinizer scrutinizer : scrutinizers.values()) {
|
||||||
scrutinizer.scrutinize(mergedUpdates);
|
scrutinizer.scrutinize(mergedUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (warningStore.getNbWarnings() == 0) {
|
if (warningStore.getNbWarnings() == 0) {
|
||||||
warningStore.addWarning(new QAWarning(
|
warningStore.addWarning(new QAWarning("no-issue-detected", null, QAWarning.Severity.INFO, 0));
|
||||||
"no-issue-detected", null, QAWarning.Severity.INFO, 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,47 +1,69 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.jsoup.helper.Validate;
|
import org.jsoup.helper.Validate;
|
||||||
import org.openrefine.wikidata.utils.JacksonJsonizable;
|
import org.openrefine.wikidata.utils.JacksonJsonizable;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to represent a QA warning emitted by the Wikidata schema
|
* A class to represent a QA warning emitted by the Wikidata schema This could
|
||||||
* This could probably be reused at a broader scale, for instance for
|
* probably be reused at a broader scale, for instance for Data Package
|
||||||
* Data Package validation.
|
* validation.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class QAWarning extends JacksonJsonizable implements Comparable<QAWarning> {
|
public class QAWarning extends JacksonJsonizable implements Comparable<QAWarning> {
|
||||||
|
|
||||||
public enum Severity {
|
public enum Severity {
|
||||||
INFO, // We just report something to the user but it is probably fine
|
INFO, // We just report something to the user but it is probably fine
|
||||||
WARNING, // Edits that look wrong but in some cases they are actually fine
|
WARNING, // Edits that look wrong but in some cases they are actually fine
|
||||||
IMPORTANT, // There is almost surely something wrong about the edit but in rare cases we might want to allow it
|
IMPORTANT, // There is almost surely something wrong about the edit but in rare cases we
|
||||||
|
// might want to allow it
|
||||||
CRITICAL, // We should never edit if there is a critical issue
|
CRITICAL, // We should never edit if there is a critical issue
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of QA warning emitted
|
/// The type of QA warning emitted
|
||||||
private final String type;
|
private final String type;
|
||||||
// The key for aggregation of other QA warnings together - this specializes the id
|
// The key for aggregation of other QA warnings together - this specializes the
|
||||||
|
// id
|
||||||
private final String bucketId;
|
private final String bucketId;
|
||||||
// The severity of the issue
|
// The severity of the issue
|
||||||
private final Severity severity;
|
private final Severity severity;
|
||||||
// The number of times this issue was found
|
// The number of times this issue was found
|
||||||
private final int count;
|
private final int count;
|
||||||
// Other details about the warning, that can be displayed to the user
|
// Other details about the warning, that can be displayed to the user
|
||||||
private final Map<String,Object> properties;
|
private final Map<String, Object> properties;
|
||||||
|
|
||||||
public QAWarning(String type, String bucketId, Severity severity, int count) {
|
public QAWarning(String type, String bucketId, Severity severity, int count) {
|
||||||
Validate.notNull(type);
|
Validate.notNull(type);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@ -51,7 +73,7 @@ public class QAWarning extends JacksonJsonizable implements Comparable<QAWarning
|
|||||||
this.count = count;
|
this.count = count;
|
||||||
this.properties = new HashMap<>();
|
this.properties = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the full key for aggregation of QA warnings
|
* @return the full key for aggregation of QA warnings
|
||||||
*/
|
*/
|
||||||
@ -63,62 +85,64 @@ public class QAWarning extends JacksonJsonizable implements Comparable<QAWarning
|
|||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregates another QA warning of the same aggregation id.
|
* Aggregates another QA warning of the same aggregation id.
|
||||||
|
*
|
||||||
* @param other
|
* @param other
|
||||||
*/
|
*/
|
||||||
public QAWarning aggregate(QAWarning other) {
|
public QAWarning aggregate(QAWarning other) {
|
||||||
assert other.getAggregationId().equals(getAggregationId());
|
assert other.getAggregationId().equals(getAggregationId());
|
||||||
int newCount = count+other.getCount();
|
int newCount = count + other.getCount();
|
||||||
Severity newSeverity = severity;
|
Severity newSeverity = severity;
|
||||||
if (other.getSeverity().compareTo(severity) > 0) {
|
if (other.getSeverity().compareTo(severity) > 0) {
|
||||||
newSeverity = other.getSeverity();
|
newSeverity = other.getSeverity();
|
||||||
}
|
}
|
||||||
QAWarning merged = new QAWarning(getType(), getBucketId(), newSeverity,
|
QAWarning merged = new QAWarning(getType(), getBucketId(), newSeverity, newCount);
|
||||||
newCount);
|
for (Entry<String, Object> entry : properties.entrySet()) {
|
||||||
for(Entry<String,Object> entry : properties.entrySet()) {
|
merged.setProperty(entry.getKey(), entry.getValue());
|
||||||
merged.setProperty(entry.getKey(),entry.getValue());
|
|
||||||
}
|
}
|
||||||
for(Entry<String,Object> entry : other.getProperties().entrySet()) {
|
for (Entry<String, Object> entry : other.getProperties().entrySet()) {
|
||||||
merged.setProperty(entry.getKey(),entry.getValue());
|
merged.setProperty(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
return merged;
|
return merged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a property of the QA warning, to be used by the front-end
|
* Sets a property of the QA warning, to be used by the front-end for display.
|
||||||
* for display.
|
*
|
||||||
* @param key: the name of the property
|
* @param key:
|
||||||
* @param value should be Jackson-serializable
|
* the name of the property
|
||||||
|
* @param value
|
||||||
|
* should be Jackson-serializable
|
||||||
*/
|
*/
|
||||||
public void setProperty(String key, Object value) {
|
public void setProperty(String key, Object value) {
|
||||||
this.properties.put(key, value);
|
this.properties.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("type")
|
@JsonProperty("type")
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("bucketId")
|
@JsonProperty("bucketId")
|
||||||
public String getBucketId() {
|
public String getBucketId() {
|
||||||
return bucketId;
|
return bucketId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("severity")
|
@JsonProperty("severity")
|
||||||
public Severity getSeverity() {
|
public Severity getSeverity() {
|
||||||
return severity;
|
return severity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("count")
|
@JsonProperty("count")
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("properties")
|
@JsonProperty("properties")
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public Map<String,Object> getProperties() {
|
public Map<String, Object> getProperties() {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,19 +151,17 @@ public class QAWarning extends JacksonJsonizable implements Comparable<QAWarning
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(QAWarning other) {
|
public int compareTo(QAWarning other) {
|
||||||
return - severity.compareTo(other.getSeverity());
|
return -severity.compareTo(other.getSeverity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null || !QAWarning.class.isInstance(other)) {
|
if (other == null || !QAWarning.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QAWarning otherWarning = (QAWarning)other;
|
QAWarning otherWarning = (QAWarning) other;
|
||||||
return type.equals(otherWarning.getType()) &&
|
return type.equals(otherWarning.getType()) && bucketId.equals(otherWarning.getBucketId())
|
||||||
bucketId.equals(otherWarning.getBucketId()) &&
|
&& severity.equals(otherWarning.getSeverity()) && count == otherWarning.getCount()
|
||||||
severity.equals(otherWarning.getSeverity()) &&
|
&& properties.equals(otherWarning.getProperties());
|
||||||
count == otherWarning.getCount() &&
|
|
||||||
properties.equals(otherWarning.getProperties());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -15,21 +38,22 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*/
|
*/
|
||||||
public class QAWarningStore {
|
public class QAWarningStore {
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private Map<String, QAWarning> map;
|
private Map<String, QAWarning> map;
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private QAWarning.Severity maxSeverity;
|
private QAWarning.Severity maxSeverity;
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private int totalWarnings;
|
private int totalWarnings;
|
||||||
|
|
||||||
public QAWarningStore() {
|
public QAWarningStore() {
|
||||||
this.map = new HashMap<>();
|
this.map = new HashMap<>();
|
||||||
this.maxSeverity = QAWarning.Severity.INFO;
|
this.maxSeverity = QAWarning.Severity.INFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a warning, aggregating it with any existing
|
* Stores a warning, aggregating it with any existing
|
||||||
|
*
|
||||||
* @param warning
|
* @param warning
|
||||||
*/
|
*/
|
||||||
public void addWarning(QAWarning warning) {
|
public void addWarning(QAWarning warning) {
|
||||||
@ -46,7 +70,7 @@ public class QAWarningStore {
|
|||||||
map.put(aggregationKey, warning);
|
map.put(aggregationKey, warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of aggregated warnings, ordered by decreasing severity
|
* Returns the list of aggregated warnings, ordered by decreasing severity
|
||||||
*/
|
*/
|
||||||
@ -56,7 +80,7 @@ public class QAWarningStore {
|
|||||||
Collections.sort(result);
|
Collections.sort(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum severity of the stored warnings (INFO if empty)
|
* Returns the maximum severity of the stored warnings (INFO if empty)
|
||||||
*/
|
*/
|
||||||
@ -64,7 +88,7 @@ public class QAWarningStore {
|
|||||||
public QAWarning.Severity getMaxSeverity() {
|
public QAWarning.Severity getMaxSeverity() {
|
||||||
return maxSeverity;
|
return maxSeverity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total number of warnings
|
* Returns the total number of warnings
|
||||||
*/
|
*/
|
||||||
|
@ -1,16 +1,36 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.openrefine.wikidata.utils.EntityCache;
|
import org.openrefine.wikidata.utils.EntityCache;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityDocument;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.PropertyDocument;
|
import org.wikidata.wdtk.datamodel.interfaces.PropertyDocument;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
||||||
@ -21,119 +41,123 @@ import org.wikidata.wdtk.datamodel.interfaces.StringValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides an abstraction over the way constraint
|
* This class provides an abstraction over the way constraint definitions are
|
||||||
* definitions are stored in Wikidata.
|
* stored in Wikidata.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WikidataConstraintFetcher implements ConstraintFetcher {
|
public class WikidataConstraintFetcher implements ConstraintFetcher {
|
||||||
|
|
||||||
public static String WIKIDATA_CONSTRAINT_PID = "P2302";
|
public static String WIKIDATA_CONSTRAINT_PID = "P2302";
|
||||||
|
|
||||||
public static String FORMAT_CONSTRAINT_QID = "Q21502404";
|
public static String FORMAT_CONSTRAINT_QID = "Q21502404";
|
||||||
public static String FORMAT_REGEX_PID = "P1793";
|
public static String FORMAT_REGEX_PID = "P1793";
|
||||||
|
|
||||||
public static String INVERSE_CONSTRAINT_QID = "Q21510855";
|
public static String INVERSE_CONSTRAINT_QID = "Q21510855";
|
||||||
public static String INVERSE_PROPERTY_PID = "P2306";
|
public static String INVERSE_PROPERTY_PID = "P2306";
|
||||||
|
|
||||||
public static String USED_ONLY_AS_VALUES_CONSTRAINT_QID = "Q21528958";
|
public static String USED_ONLY_AS_VALUES_CONSTRAINT_QID = "Q21528958";
|
||||||
|
|
||||||
public static String USED_ONLY_AS_QUALIFIER_CONSTRAINT_QID = "Q21510863";
|
public static String USED_ONLY_AS_QUALIFIER_CONSTRAINT_QID = "Q21510863";
|
||||||
|
|
||||||
public static String USED_ONLY_AS_REFERENCE_CONSTRAINT_QID = "Q21528959";
|
public static String USED_ONLY_AS_REFERENCE_CONSTRAINT_QID = "Q21528959";
|
||||||
|
|
||||||
public static String ALLOWED_QUALIFIERS_CONSTRAINT_QID = "Q21510851";
|
public static String ALLOWED_QUALIFIERS_CONSTRAINT_QID = "Q21510851";
|
||||||
public static String ALLOWED_QUALIFIERS_CONSTRAINT_PID = "P2306";
|
public static String ALLOWED_QUALIFIERS_CONSTRAINT_PID = "P2306";
|
||||||
|
|
||||||
public static String MANDATORY_QUALIFIERS_CONSTRAINT_QID = "Q21510856";
|
public static String MANDATORY_QUALIFIERS_CONSTRAINT_QID = "Q21510856";
|
||||||
public static String MANDATORY_QUALIFIERS_CONSTRAINT_PID = "P2306";
|
public static String MANDATORY_QUALIFIERS_CONSTRAINT_PID = "P2306";
|
||||||
|
|
||||||
public static String SINGLE_VALUE_CONSTRAINT_QID = "Q19474404";
|
public static String SINGLE_VALUE_CONSTRAINT_QID = "Q19474404";
|
||||||
public static String DISTINCT_VALUES_CONSTRAINT_QID = "Q21502410";
|
public static String DISTINCT_VALUES_CONSTRAINT_QID = "Q21502410";
|
||||||
|
|
||||||
// The following constraints still need to be implemented:
|
// The following constraints still need to be implemented:
|
||||||
|
|
||||||
public static String TYPE_CONSTRAINT_QID = "Q21503250";
|
public static String TYPE_CONSTRAINT_QID = "Q21503250";
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFormatRegex(PropertyIdValue pid) {
|
public String getFormatRegex(PropertyIdValue pid) {
|
||||||
List<SnakGroup> specs = getSingleConstraint(pid, FORMAT_CONSTRAINT_QID);
|
List<SnakGroup> specs = getSingleConstraint(pid, FORMAT_CONSTRAINT_QID);
|
||||||
if (specs != null) {
|
if (specs != null) {
|
||||||
List<Value> regexes = findValues(specs, FORMAT_REGEX_PID);
|
List<Value> regexes = findValues(specs, FORMAT_REGEX_PID);
|
||||||
if (! regexes.isEmpty()) {
|
if (!regexes.isEmpty()) {
|
||||||
return ((StringValue)regexes.get(0)).getString();
|
return ((StringValue) regexes.get(0)).getString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PropertyIdValue getInversePid(PropertyIdValue pid) {
|
public PropertyIdValue getInversePid(PropertyIdValue pid) {
|
||||||
List<SnakGroup> specs = getSingleConstraint(pid, INVERSE_CONSTRAINT_QID);
|
List<SnakGroup> specs = getSingleConstraint(pid, INVERSE_CONSTRAINT_QID);
|
||||||
|
|
||||||
if(specs != null) {
|
if (specs != null) {
|
||||||
List<Value> inverses = findValues(specs, INVERSE_PROPERTY_PID);
|
List<Value> inverses = findValues(specs, INVERSE_PROPERTY_PID);
|
||||||
if (! inverses.isEmpty()) {
|
if (!inverses.isEmpty()) {
|
||||||
return (PropertyIdValue)inverses.get(0);
|
return (PropertyIdValue) inverses.get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isForValuesOnly(PropertyIdValue pid) {
|
public boolean isForValuesOnly(PropertyIdValue pid) {
|
||||||
return getSingleConstraint(pid, USED_ONLY_AS_VALUES_CONSTRAINT_QID) != null;
|
return getSingleConstraint(pid, USED_ONLY_AS_VALUES_CONSTRAINT_QID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isForQualifiersOnly(PropertyIdValue pid) {
|
public boolean isForQualifiersOnly(PropertyIdValue pid) {
|
||||||
return getSingleConstraint(pid, USED_ONLY_AS_QUALIFIER_CONSTRAINT_QID) != null;
|
return getSingleConstraint(pid, USED_ONLY_AS_QUALIFIER_CONSTRAINT_QID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isForReferencesOnly(PropertyIdValue pid) {
|
public boolean isForReferencesOnly(PropertyIdValue pid) {
|
||||||
return getSingleConstraint(pid, USED_ONLY_AS_REFERENCE_CONSTRAINT_QID) != null;
|
return getSingleConstraint(pid, USED_ONLY_AS_REFERENCE_CONSTRAINT_QID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<PropertyIdValue> allowedQualifiers(PropertyIdValue pid) {
|
public Set<PropertyIdValue> allowedQualifiers(PropertyIdValue pid) {
|
||||||
List<SnakGroup> specs = getSingleConstraint(pid, ALLOWED_QUALIFIERS_CONSTRAINT_QID);
|
List<SnakGroup> specs = getSingleConstraint(pid, ALLOWED_QUALIFIERS_CONSTRAINT_QID);
|
||||||
|
|
||||||
if (specs != null) {
|
if (specs != null) {
|
||||||
List<Value> properties = findValues(specs, ALLOWED_QUALIFIERS_CONSTRAINT_PID);
|
List<Value> properties = findValues(specs, ALLOWED_QUALIFIERS_CONSTRAINT_PID);
|
||||||
return properties.stream().map(e -> (PropertyIdValue) e).collect(Collectors.toSet());
|
return properties.stream().map(e -> (PropertyIdValue) e).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue pid) {
|
public Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue pid) {
|
||||||
List<SnakGroup> specs = getSingleConstraint(pid, MANDATORY_QUALIFIERS_CONSTRAINT_QID);
|
List<SnakGroup> specs = getSingleConstraint(pid, MANDATORY_QUALIFIERS_CONSTRAINT_QID);
|
||||||
|
|
||||||
if (specs != null) {
|
if (specs != null) {
|
||||||
List<Value> properties = findValues(specs, MANDATORY_QUALIFIERS_CONSTRAINT_PID);
|
List<Value> properties = findValues(specs, MANDATORY_QUALIFIERS_CONSTRAINT_PID);
|
||||||
return properties.stream().map(e -> (PropertyIdValue) e).collect(Collectors.toSet());
|
return properties.stream().map(e -> (PropertyIdValue) e).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSingleValue(PropertyIdValue pid) {
|
public boolean hasSingleValue(PropertyIdValue pid) {
|
||||||
return getSingleConstraint(pid, SINGLE_VALUE_CONSTRAINT_QID) != null;
|
return getSingleConstraint(pid, SINGLE_VALUE_CONSTRAINT_QID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasDistinctValues(PropertyIdValue pid) {
|
public boolean hasDistinctValues(PropertyIdValue pid) {
|
||||||
return getSingleConstraint(pid, DISTINCT_VALUES_CONSTRAINT_QID) != null;
|
return getSingleConstraint(pid, DISTINCT_VALUES_CONSTRAINT_QID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a single constraint for a particular type and a property, or null
|
* Returns a single constraint for a particular type and a property, or null if
|
||||||
* if there is no such constraint
|
* there is no such constraint
|
||||||
* @param pid: the property to retrieve the constraints for
|
*
|
||||||
* @param qid: the type of the constraints
|
* @param pid:
|
||||||
* @return the list of qualifiers for the constraint, or null if it does not exist
|
* the property to retrieve the constraints for
|
||||||
|
* @param qid:
|
||||||
|
* the type of the constraints
|
||||||
|
* @return the list of qualifiers for the constraint, or null if it does not
|
||||||
|
* exist
|
||||||
*/
|
*/
|
||||||
protected List<SnakGroup> getSingleConstraint(PropertyIdValue pid, String qid) {
|
protected List<SnakGroup> getSingleConstraint(PropertyIdValue pid, String qid) {
|
||||||
Statement statement = getConstraintsByType(pid, qid).findFirst().orElse(null);
|
Statement statement = getConstraintsByType(pid, qid).findFirst().orElse(null);
|
||||||
@ -142,23 +166,27 @@ public class WikidataConstraintFetcher implements ConstraintFetcher {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of constraints of a particular type for a property
|
* Gets the list of constraints of a particular type for a property
|
||||||
* @param pid: the property to retrieve the constraints for
|
*
|
||||||
* @param qid: the type of the constraints
|
* @param pid:
|
||||||
|
* the property to retrieve the constraints for
|
||||||
|
* @param qid:
|
||||||
|
* the type of the constraints
|
||||||
* @return the stream of matching constraint statements
|
* @return the stream of matching constraint statements
|
||||||
*/
|
*/
|
||||||
protected Stream<Statement> getConstraintsByType(PropertyIdValue pid, String qid) {
|
protected Stream<Statement> getConstraintsByType(PropertyIdValue pid, String qid) {
|
||||||
Stream<Statement> allConstraints = getConstraintStatements(pid)
|
Stream<Statement> allConstraints = getConstraintStatements(pid).stream()
|
||||||
.stream()
|
|
||||||
.filter(s -> ((EntityIdValue) s.getValue()).getId().equals(qid));
|
.filter(s -> ((EntityIdValue) s.getValue()).getId().equals(qid));
|
||||||
return allConstraints;
|
return allConstraints;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all the constraint statements for a given property
|
* Gets all the constraint statements for a given property
|
||||||
* @param pid : the id of the property to retrieve the constraints for
|
*
|
||||||
|
* @param pid
|
||||||
|
* : the id of the property to retrieve the constraints for
|
||||||
* @return the list of constraint statements
|
* @return the list of constraint statements
|
||||||
*/
|
*/
|
||||||
protected List<Statement> getConstraintStatements(PropertyIdValue pid) {
|
protected List<Statement> getConstraintStatements(PropertyIdValue pid) {
|
||||||
@ -170,16 +198,19 @@ public class WikidataConstraintFetcher implements ConstraintFetcher {
|
|||||||
return new ArrayList<Statement>();
|
return new ArrayList<Statement>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the values of a given property in qualifiers
|
* Returns the values of a given property in qualifiers
|
||||||
* @param groups: the qualifiers
|
*
|
||||||
* @param pid: the property to filter on
|
* @param groups:
|
||||||
|
* the qualifiers
|
||||||
|
* @param pid:
|
||||||
|
* the property to filter on
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected List<Value> findValues(List<SnakGroup> groups, String pid) {
|
protected List<Value> findValues(List<SnakGroup> groups, String pid) {
|
||||||
List<Value> results = new ArrayList<>();
|
List<Value> results = new ArrayList<>();
|
||||||
for(SnakGroup group : groups) {
|
for (SnakGroup group : groups) {
|
||||||
if (group.getProperty().getId().equals(pid)) {
|
if (group.getProperty().getId().equals(pid)) {
|
||||||
for (Snak snak : group.getSnaks())
|
for (Snak snak : group.getSnaks())
|
||||||
results.add(snak.getValue());
|
results.add(snak.getValue());
|
||||||
|
@ -1,9 +1,30 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.openrefine.wikidata.qa.QAWarning;
|
import org.openrefine.wikidata.qa.QAWarning;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
||||||
@ -12,18 +33,18 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scrutinizer that checks for properties using the same value
|
* A scrutinizer that checks for properties using the same value on different
|
||||||
* on different items.
|
* items.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class DistinctValuesScrutinizer extends StatementScrutinizer {
|
public class DistinctValuesScrutinizer extends StatementScrutinizer {
|
||||||
|
|
||||||
public final static String type = "identical-values-for-distinct-valued-property";
|
public final static String type = "identical-values-for-distinct-valued-property";
|
||||||
|
|
||||||
private Map<PropertyIdValue, Map<Value, EntityIdValue>> _seenValues;
|
private Map<PropertyIdValue, Map<Value, EntityIdValue>> _seenValues;
|
||||||
|
|
||||||
public DistinctValuesScrutinizer() {
|
public DistinctValuesScrutinizer() {
|
||||||
_seenValues = new HashMap<>();
|
_seenValues = new HashMap<>();
|
||||||
}
|
}
|
||||||
@ -40,11 +61,7 @@ public class DistinctValuesScrutinizer extends StatementScrutinizer {
|
|||||||
}
|
}
|
||||||
if (seen.containsKey(mainSnakValue)) {
|
if (seen.containsKey(mainSnakValue)) {
|
||||||
EntityIdValue otherId = seen.get(mainSnakValue);
|
EntityIdValue otherId = seen.get(mainSnakValue);
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(type, pid.getId(), QAWarning.Severity.IMPORTANT, 1);
|
||||||
type,
|
|
||||||
pid.getId(),
|
|
||||||
QAWarning.Severity.IMPORTANT,
|
|
||||||
1);
|
|
||||||
issue.setProperty("property_entity", pid);
|
issue.setProperty("property_entity", pid);
|
||||||
issue.setProperty("item1_entity", entityId);
|
issue.setProperty("item1_entity", entityId);
|
||||||
issue.setProperty("item2_entity", otherId);
|
issue.setProperty("item2_entity", otherId);
|
||||||
|
@ -1,8 +1,30 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.openrefine.wikidata.qa.WikidataConstraintFetcher;
|
|
||||||
import org.openrefine.wikidata.qa.ConstraintFetcher;
|
import org.openrefine.wikidata.qa.ConstraintFetcher;
|
||||||
import org.openrefine.wikidata.qa.QAWarning;
|
import org.openrefine.wikidata.qa.QAWarning;
|
||||||
import org.openrefine.wikidata.qa.QAWarning.Severity;
|
import org.openrefine.wikidata.qa.QAWarning.Severity;
|
||||||
@ -15,64 +37,70 @@ import org.openrefine.wikidata.updates.ItemUpdate;
|
|||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*/
|
*/
|
||||||
public abstract class EditScrutinizer {
|
public abstract class EditScrutinizer {
|
||||||
|
|
||||||
protected QAWarningStore _store;
|
protected QAWarningStore _store;
|
||||||
protected ConstraintFetcher _fetcher;
|
protected ConstraintFetcher _fetcher;
|
||||||
|
|
||||||
public EditScrutinizer() {
|
public EditScrutinizer() {
|
||||||
_fetcher = null;
|
_fetcher = null;
|
||||||
_store = null;
|
_store = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStore(QAWarningStore store) {
|
public void setStore(QAWarningStore store) {
|
||||||
_store = store;
|
_store = store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFetcher(ConstraintFetcher fetcher) {
|
public void setFetcher(ConstraintFetcher fetcher) {
|
||||||
_fetcher = fetcher;
|
_fetcher = fetcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the candidate edits and emits warnings in the store
|
* Reads the candidate edits and emits warnings in the store
|
||||||
* @param edit: the list of ItemUpdates to scrutinize
|
*
|
||||||
|
* @param edit:
|
||||||
|
* the list of ItemUpdates to scrutinize
|
||||||
*/
|
*/
|
||||||
public abstract void scrutinize(List<ItemUpdate> edit);
|
public abstract void scrutinize(List<ItemUpdate> edit);
|
||||||
|
|
||||||
protected void addIssue(QAWarning warning) {
|
protected void addIssue(QAWarning warning) {
|
||||||
_store.addWarning(warning);
|
_store.addWarning(warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addIssue(String type, String aggregationId, Severity severity, int count) {
|
protected void addIssue(String type, String aggregationId, Severity severity, int count) {
|
||||||
addIssue(new QAWarning(type, aggregationId, severity, count));
|
addIssue(new QAWarning(type, aggregationId, severity, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to be used by subclasses to emit simple INFO warnings
|
* Helper to be used by subclasses to emit simple INFO warnings
|
||||||
|
*
|
||||||
* @param warning
|
* @param warning
|
||||||
*/
|
*/
|
||||||
protected void info(String type) {
|
protected void info(String type) {
|
||||||
addIssue(type, null, QAWarning.Severity.INFO, 1);
|
addIssue(type, null, QAWarning.Severity.INFO, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to be used by subclasses to emit simple warnings
|
* Helper to be used by subclasses to emit simple warnings
|
||||||
|
*
|
||||||
* @param warning
|
* @param warning
|
||||||
*/
|
*/
|
||||||
protected void warning(String type) {
|
protected void warning(String type) {
|
||||||
addIssue(type, null, QAWarning.Severity.WARNING, 1);
|
addIssue(type, null, QAWarning.Severity.WARNING, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to be used by subclasses to emit simple important warnings
|
* Helper to be used by subclasses to emit simple important warnings
|
||||||
|
*
|
||||||
* @param warning
|
* @param warning
|
||||||
*/
|
*/
|
||||||
protected void important(String type) {
|
protected void important(String type) {
|
||||||
addIssue(type, null, QAWarning.Severity.IMPORTANT, 1);
|
addIssue(type, null, QAWarning.Severity.IMPORTANT, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to be used by subclasses to emit simple critical warnings
|
* Helper to be used by subclasses to emit simple critical warnings
|
||||||
|
*
|
||||||
* @param warning
|
* @param warning
|
||||||
*/
|
*/
|
||||||
protected void critical(String type) {
|
protected void critical(String type) {
|
||||||
|
@ -1,8 +1,30 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.openrefine.wikidata.qa.QAWarning;
|
import org.openrefine.wikidata.qa.QAWarning;
|
||||||
@ -12,31 +34,32 @@ import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.StringValue;
|
import org.wikidata.wdtk.datamodel.interfaces.StringValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scrutinizer that detects incorrect formats in text values
|
* A scrutinizer that detects incorrect formats in text values (mostly
|
||||||
* (mostly identifiers).
|
* identifiers).
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class FormatScrutinizer extends SnakScrutinizer {
|
public class FormatScrutinizer extends SnakScrutinizer {
|
||||||
|
|
||||||
public static final String type = "add-statements-with-invalid-format";
|
public static final String type = "add-statements-with-invalid-format";
|
||||||
|
|
||||||
private Map<PropertyIdValue, Pattern> _patterns;
|
private Map<PropertyIdValue, Pattern> _patterns;
|
||||||
|
|
||||||
public FormatScrutinizer() {
|
public FormatScrutinizer() {
|
||||||
_patterns = new HashMap<>();
|
_patterns = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the regex for a property and compiles it to a pattern
|
* Loads the regex for a property and compiles it to a pattern (this is cached
|
||||||
* (this is cached upstream, plus we are doing it only once per
|
* upstream, plus we are doing it only once per property and batch).
|
||||||
* property and batch).
|
*
|
||||||
* @param pid the id of the property to fetch the constraints for
|
* @param pid
|
||||||
|
* the id of the property to fetch the constraints for
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected Pattern getPattern(PropertyIdValue pid) {
|
protected Pattern getPattern(PropertyIdValue pid) {
|
||||||
if(_patterns.containsKey(pid)) {
|
if (_patterns.containsKey(pid)) {
|
||||||
return _patterns.get(pid);
|
return _patterns.get(pid);
|
||||||
} else {
|
} else {
|
||||||
String regex = _fetcher.getFormatRegex(pid);
|
String regex = _fetcher.getFormatRegex(pid);
|
||||||
@ -51,7 +74,7 @@ public class FormatScrutinizer extends SnakScrutinizer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(Snak snak, EntityIdValue entityId, boolean added) {
|
public void scrutinize(Snak snak, EntityIdValue entityId, boolean added) {
|
||||||
if(StringValue.class.isInstance(snak.getValue())) {
|
if (StringValue.class.isInstance(snak.getValue())) {
|
||||||
String value = ((StringValue) snak.getValue()).getString();
|
String value = ((StringValue) snak.getValue()).getString();
|
||||||
PropertyIdValue pid = snak.getPropertyId();
|
PropertyIdValue pid = snak.getPropertyId();
|
||||||
Pattern pattern = getPattern(pid);
|
Pattern pattern = getPattern(pid);
|
||||||
@ -60,11 +83,7 @@ public class FormatScrutinizer extends SnakScrutinizer {
|
|||||||
}
|
}
|
||||||
if (!pattern.matcher(value).matches()) {
|
if (!pattern.matcher(value).matches()) {
|
||||||
if (added) {
|
if (added) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(type, pid.getId(), QAWarning.Severity.IMPORTANT, 1);
|
||||||
type,
|
|
||||||
pid.getId(),
|
|
||||||
QAWarning.Severity.IMPORTANT,
|
|
||||||
1);
|
|
||||||
issue.setProperty("property_entity", pid);
|
issue.setProperty("property_entity", pid);
|
||||||
issue.setProperty("regex", pattern.toString());
|
issue.setProperty("regex", pattern.toString());
|
||||||
issue.setProperty("example_value", value);
|
issue.setProperty("example_value", value);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -14,48 +37,47 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scrutinizer that checks for missing inverse statements in
|
* A scrutinizer that checks for missing inverse statements in edit batches.
|
||||||
* edit batches.
|
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class InverseConstraintScrutinizer extends StatementScrutinizer {
|
public class InverseConstraintScrutinizer extends StatementScrutinizer {
|
||||||
|
|
||||||
public static final String type = "missing-inverse-statements";
|
public static final String type = "missing-inverse-statements";
|
||||||
|
|
||||||
private Map<PropertyIdValue, PropertyIdValue> _inverse;
|
private Map<PropertyIdValue, PropertyIdValue> _inverse;
|
||||||
private Map<PropertyIdValue, Map<EntityIdValue, Set<EntityIdValue> >> _statements;
|
private Map<PropertyIdValue, Map<EntityIdValue, Set<EntityIdValue>>> _statements;
|
||||||
|
|
||||||
public InverseConstraintScrutinizer() {
|
public InverseConstraintScrutinizer() {
|
||||||
_inverse = new HashMap<>();
|
_inverse = new HashMap<>();
|
||||||
_statements = new HashMap<>();
|
_statements = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PropertyIdValue getInverseConstraint(PropertyIdValue pid) {
|
protected PropertyIdValue getInverseConstraint(PropertyIdValue pid) {
|
||||||
if (_inverse.containsKey(pid)) {
|
if (_inverse.containsKey(pid)) {
|
||||||
return _inverse.get(pid);
|
return _inverse.get(pid);
|
||||||
} else {
|
} else {
|
||||||
PropertyIdValue inversePid = _fetcher.getInversePid(pid);
|
PropertyIdValue inversePid = _fetcher.getInversePid(pid);
|
||||||
_inverse.put(pid, inversePid);
|
_inverse.put(pid, inversePid);
|
||||||
_statements.put(pid, new HashMap<EntityIdValue,Set<EntityIdValue>>());
|
_statements.put(pid, new HashMap<EntityIdValue, Set<EntityIdValue>>());
|
||||||
|
|
||||||
// We are doing this check because we do not have any guarantee that
|
// We are doing this check because we do not have any guarantee that
|
||||||
// the inverse constraints are consistent on Wikidata.
|
// the inverse constraints are consistent on Wikidata.
|
||||||
if (inversePid != null && !_inverse.containsKey(inversePid)) {
|
if (inversePid != null && !_inverse.containsKey(inversePid)) {
|
||||||
_inverse.put(inversePid, pid);
|
_inverse.put(inversePid, pid);
|
||||||
_statements.put(inversePid, new HashMap<EntityIdValue,Set<EntityIdValue>>());
|
_statements.put(inversePid, new HashMap<EntityIdValue, Set<EntityIdValue>>());
|
||||||
}
|
}
|
||||||
return inversePid;
|
return inversePid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
||||||
if (!added) {
|
if (!added) {
|
||||||
return; // TODO support for deleted statements
|
return; // TODO support for deleted statements
|
||||||
}
|
}
|
||||||
|
|
||||||
Value mainSnakValue = statement.getClaim().getMainSnak().getValue();
|
Value mainSnakValue = statement.getClaim().getMainSnak().getValue();
|
||||||
if (ItemIdValue.class.isInstance(mainSnakValue)) {
|
if (ItemIdValue.class.isInstance(mainSnakValue)) {
|
||||||
PropertyIdValue pid = statement.getClaim().getMainSnak().getPropertyId();
|
PropertyIdValue pid = statement.getClaim().getMainSnak().getPropertyId();
|
||||||
@ -71,24 +93,21 @@ public class InverseConstraintScrutinizer extends StatementScrutinizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void batchIsFinished() {
|
public void batchIsFinished() {
|
||||||
// For each pair of inverse properties (in each direction)
|
// For each pair of inverse properties (in each direction)
|
||||||
for(Entry<PropertyIdValue,PropertyIdValue> propertyPair : _inverse.entrySet()) {
|
for (Entry<PropertyIdValue, PropertyIdValue> propertyPair : _inverse.entrySet()) {
|
||||||
// Get the statements made for the first
|
// Get the statements made for the first
|
||||||
PropertyIdValue ourProperty = propertyPair.getKey();
|
PropertyIdValue ourProperty = propertyPair.getKey();
|
||||||
for(Entry<EntityIdValue, Set<EntityIdValue>> itemLinks : _statements.get(ourProperty).entrySet()) {
|
for (Entry<EntityIdValue, Set<EntityIdValue>> itemLinks : _statements.get(ourProperty).entrySet()) {
|
||||||
// For each outgoing link
|
// For each outgoing link
|
||||||
for(EntityIdValue idValue : itemLinks.getValue()) {
|
for (EntityIdValue idValue : itemLinks.getValue()) {
|
||||||
// Check that they are in the statements made for the second
|
// Check that they are in the statements made for the second
|
||||||
PropertyIdValue missingProperty = propertyPair.getValue();
|
PropertyIdValue missingProperty = propertyPair.getValue();
|
||||||
Set<EntityIdValue> reciprocalLinks = _statements.get(missingProperty).get(idValue);
|
Set<EntityIdValue> reciprocalLinks = _statements.get(missingProperty).get(idValue);
|
||||||
if (reciprocalLinks == null || !reciprocalLinks.contains(itemLinks.getKey())) {
|
if (reciprocalLinks == null || !reciprocalLinks.contains(itemLinks.getKey())) {
|
||||||
QAWarning issue = new QAWarning(type,
|
QAWarning issue = new QAWarning(type, ourProperty.getId(), QAWarning.Severity.IMPORTANT, 1);
|
||||||
ourProperty.getId(),
|
|
||||||
QAWarning.Severity.IMPORTANT,
|
|
||||||
1);
|
|
||||||
issue.setProperty("added_property_entity", ourProperty);
|
issue.setProperty("added_property_entity", ourProperty);
|
||||||
issue.setProperty("inverse_property_entity", missingProperty);
|
issue.setProperty("inverse_property_entity", missingProperty);
|
||||||
issue.setProperty("source_entity", itemLinks.getKey());
|
issue.setProperty("source_entity", itemLinks.getKey());
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -8,8 +31,8 @@ public abstract class ItemUpdateScrutinizer extends EditScrutinizer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(List<ItemUpdate> edit) {
|
public void scrutinize(List<ItemUpdate> edit) {
|
||||||
for(ItemUpdate update : edit) {
|
for (ItemUpdate update : edit) {
|
||||||
if(!update.isNull()) {
|
if (!update.isNull()) {
|
||||||
scrutinize(update);
|
scrutinize(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,15 +40,16 @@ public abstract class ItemUpdateScrutinizer extends EditScrutinizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to be overridden by subclasses to scrutinize
|
* Method to be overridden by subclasses to scrutinize an individual item
|
||||||
* an individual item update.
|
* update.
|
||||||
|
*
|
||||||
* @param update
|
* @param update
|
||||||
*/
|
*/
|
||||||
public abstract void scrutinize(ItemUpdate update);
|
public abstract void scrutinize(ItemUpdate update);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to be overridden by subclasses to emit warnings
|
* Method to be overridden by subclasses to emit warnings once a batch has been
|
||||||
* once a batch has been completely analyzed.
|
* completely analyzed.
|
||||||
*/
|
*/
|
||||||
public void batchIsFinished() {
|
public void batchIsFinished() {
|
||||||
;
|
;
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.openrefine.wikidata.qa.QAWarning;
|
import org.openrefine.wikidata.qa.QAWarning;
|
||||||
@ -10,7 +33,7 @@ import org.wikidata.wdtk.datamodel.interfaces.StatementGroup;
|
|||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*/
|
*/
|
||||||
public class NewItemScrutinizer extends ItemUpdateScrutinizer {
|
public class NewItemScrutinizer extends ItemUpdateScrutinizer {
|
||||||
|
|
||||||
public static final String noLabelType = "new-item-without-labels-or-aliases";
|
public static final String noLabelType = "new-item-without-labels-or-aliases";
|
||||||
public static final String noDescType = "new-item-without-descriptions";
|
public static final String noDescType = "new-item-without-descriptions";
|
||||||
public static final String deletedStatementsType = "new-item-with-deleted-statements";
|
public static final String deletedStatementsType = "new-item-with-deleted-statements";
|
||||||
@ -21,40 +44,28 @@ public class NewItemScrutinizer extends ItemUpdateScrutinizer {
|
|||||||
public void scrutinize(ItemUpdate update) {
|
public void scrutinize(ItemUpdate update) {
|
||||||
if (update.isNew()) {
|
if (update.isNew()) {
|
||||||
info(newItemType);
|
info(newItemType);
|
||||||
|
|
||||||
if (update.getLabels().isEmpty() && update.getAliases().isEmpty()) {
|
if (update.getLabels().isEmpty() && update.getAliases().isEmpty()) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(noLabelType, null, QAWarning.Severity.CRITICAL, 1);
|
||||||
noLabelType,
|
|
||||||
null,
|
|
||||||
QAWarning.Severity.CRITICAL,
|
|
||||||
1);
|
|
||||||
issue.setProperty("example_entity", update.getItemId());
|
issue.setProperty("example_entity", update.getItemId());
|
||||||
addIssue(issue);
|
addIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update.getDescriptions().isEmpty()) {
|
if (update.getDescriptions().isEmpty()) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(noDescType, null, QAWarning.Severity.WARNING, 1);
|
||||||
noDescType,
|
|
||||||
null,
|
|
||||||
QAWarning.Severity.WARNING,
|
|
||||||
1);
|
|
||||||
issue.setProperty("example_entity", update.getItemId());
|
issue.setProperty("example_entity", update.getItemId());
|
||||||
addIssue(issue);
|
addIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!update.getDeletedStatements().isEmpty()) {
|
if (!update.getDeletedStatements().isEmpty()) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(deletedStatementsType, null, QAWarning.Severity.WARNING, 1);
|
||||||
deletedStatementsType,
|
|
||||||
null,
|
|
||||||
QAWarning.Severity.WARNING,
|
|
||||||
1);
|
|
||||||
issue.setProperty("example_entity", update.getItemId());
|
issue.setProperty("example_entity", update.getItemId());
|
||||||
addIssue(issue);
|
addIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find a "instance of" or "subclass of" claim
|
// Try to find a "instance of" or "subclass of" claim
|
||||||
boolean typeFound = false;
|
boolean typeFound = false;
|
||||||
for(StatementGroup group : update.getAddedStatementGroups()) {
|
for (StatementGroup group : update.getAddedStatementGroups()) {
|
||||||
String pid = group.getProperty().getId();
|
String pid = group.getProperty().getId();
|
||||||
if ("P31".equals(pid) || "P279".equals(pid)) {
|
if ("P31".equals(pid) || "P279".equals(pid)) {
|
||||||
typeFound = true;
|
typeFound = true;
|
||||||
@ -62,13 +73,9 @@ public class NewItemScrutinizer extends ItemUpdateScrutinizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!typeFound) {
|
if (!typeFound) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(noTypeType, null, QAWarning.Severity.WARNING, 1);
|
||||||
noTypeType,
|
issue.setProperty("example_entity", update.getItemId());
|
||||||
null,
|
addIssue(issue);
|
||||||
QAWarning.Severity.WARNING,
|
|
||||||
1);
|
|
||||||
issue.setProperty("example_entity", update.getItemId());
|
|
||||||
addIssue(issue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,39 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
|
|
||||||
|
|
||||||
public class NoEditsMadeScrutinizer extends EditScrutinizer {
|
public class NoEditsMadeScrutinizer extends EditScrutinizer {
|
||||||
|
|
||||||
public static final String type = "no-edit-generated";
|
public static final String type = "no-edit-generated";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(List<ItemUpdate> edit) {
|
public void scrutinize(List<ItemUpdate> edit) {
|
||||||
if(edit.stream().allMatch(e -> e.isNull())) {
|
if (edit.stream().allMatch(e -> e.isNull())) {
|
||||||
info(type);
|
info(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -12,24 +35,24 @@ import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scrutinizer that checks the compatibility of the qualifiers
|
* A scrutinizer that checks the compatibility of the qualifiers and the
|
||||||
* and the property of a statement, and looks for mandatory qualifiers.
|
* property of a statement, and looks for mandatory qualifiers.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*/
|
*/
|
||||||
public class QualifierCompatibilityScrutinizer extends StatementScrutinizer {
|
public class QualifierCompatibilityScrutinizer extends StatementScrutinizer {
|
||||||
|
|
||||||
public static final String missingMandatoryQualifiersType = "missing-mandatory-qualifiers";
|
public static final String missingMandatoryQualifiersType = "missing-mandatory-qualifiers";
|
||||||
public static final String disallowedQualifiersType = "disallowed-qualifiers";
|
public static final String disallowedQualifiersType = "disallowed-qualifiers";
|
||||||
|
|
||||||
private Map<PropertyIdValue, Set<PropertyIdValue>> _allowedQualifiers;
|
private Map<PropertyIdValue, Set<PropertyIdValue>> _allowedQualifiers;
|
||||||
private Map<PropertyIdValue, Set<PropertyIdValue>> _mandatoryQualifiers;
|
private Map<PropertyIdValue, Set<PropertyIdValue>> _mandatoryQualifiers;
|
||||||
|
|
||||||
public QualifierCompatibilityScrutinizer() {
|
public QualifierCompatibilityScrutinizer() {
|
||||||
_allowedQualifiers = new HashMap<>();
|
_allowedQualifiers = new HashMap<>();
|
||||||
_mandatoryQualifiers = new HashMap<>();
|
_mandatoryQualifiers = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean qualifierIsAllowed(PropertyIdValue statementProperty, PropertyIdValue qualifierProperty) {
|
protected boolean qualifierIsAllowed(PropertyIdValue statementProperty, PropertyIdValue qualifierProperty) {
|
||||||
Set<PropertyIdValue> allowed = null;
|
Set<PropertyIdValue> allowed = null;
|
||||||
if (_allowedQualifiers.containsKey(statementProperty)) {
|
if (_allowedQualifiers.containsKey(statementProperty)) {
|
||||||
@ -40,7 +63,7 @@ public class QualifierCompatibilityScrutinizer extends StatementScrutinizer {
|
|||||||
}
|
}
|
||||||
return allowed == null || allowed.contains(qualifierProperty);
|
return allowed == null || allowed.contains(qualifierProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue statementProperty) {
|
protected Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue statementProperty) {
|
||||||
Set<PropertyIdValue> mandatory = null;
|
Set<PropertyIdValue> mandatory = null;
|
||||||
if (_mandatoryQualifiers.containsKey(statementProperty)) {
|
if (_mandatoryQualifiers.containsKey(statementProperty)) {
|
||||||
@ -58,31 +81,25 @@ public class QualifierCompatibilityScrutinizer extends StatementScrutinizer {
|
|||||||
@Override
|
@Override
|
||||||
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
||||||
PropertyIdValue statementProperty = statement.getClaim().getMainSnak().getPropertyId();
|
PropertyIdValue statementProperty = statement.getClaim().getMainSnak().getPropertyId();
|
||||||
Set<PropertyIdValue> qualifiers = statement.getClaim().getQualifiers().
|
Set<PropertyIdValue> qualifiers = statement.getClaim().getQualifiers().stream().map(e -> e.getProperty())
|
||||||
stream().map(e -> e.getProperty()).collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
Set<PropertyIdValue> missingQualifiers = mandatoryQualifiers(statementProperty)
|
Set<PropertyIdValue> missingQualifiers = mandatoryQualifiers(statementProperty).stream()
|
||||||
.stream().filter(p -> !qualifiers.contains(p)).collect(Collectors.toSet());
|
.filter(p -> !qualifiers.contains(p)).collect(Collectors.toSet());
|
||||||
Set<PropertyIdValue> disallowedQualifiers = qualifiers
|
Set<PropertyIdValue> disallowedQualifiers = qualifiers.stream()
|
||||||
.stream().filter(p -> !qualifierIsAllowed(statementProperty, p)).collect(Collectors.toSet());
|
.filter(p -> !qualifierIsAllowed(statementProperty, p)).collect(Collectors.toSet());
|
||||||
|
|
||||||
for (PropertyIdValue missing : missingQualifiers) {
|
for (PropertyIdValue missing : missingQualifiers) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(missingMandatoryQualifiersType,
|
||||||
missingMandatoryQualifiersType,
|
statementProperty.getId() + "-" + missing.getId(), QAWarning.Severity.WARNING, 1);
|
||||||
statementProperty.getId()+"-"+missing.getId(),
|
|
||||||
QAWarning.Severity.WARNING,
|
|
||||||
1);
|
|
||||||
issue.setProperty("statement_property_entity", statementProperty);
|
issue.setProperty("statement_property_entity", statementProperty);
|
||||||
issue.setProperty("missing_property_entity", missing);
|
issue.setProperty("missing_property_entity", missing);
|
||||||
issue.setProperty("example_item_entity", entityId);
|
issue.setProperty("example_item_entity", entityId);
|
||||||
addIssue(issue);
|
addIssue(issue);
|
||||||
}
|
}
|
||||||
for (PropertyIdValue disallowed : disallowedQualifiers) {
|
for (PropertyIdValue disallowed : disallowedQualifiers) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(disallowedQualifiersType,
|
||||||
disallowedQualifiersType,
|
statementProperty.getId() + "-" + disallowed.getId(), QAWarning.Severity.WARNING, 1);
|
||||||
statementProperty.getId()+"-"+disallowed.getId(),
|
|
||||||
QAWarning.Severity.WARNING,
|
|
||||||
1);
|
|
||||||
issue.setProperty("statement_property_entity", statementProperty);
|
issue.setProperty("statement_property_entity", statementProperty);
|
||||||
issue.setProperty("disallowed_property_entity", disallowed);
|
issue.setProperty("disallowed_property_entity", disallowed);
|
||||||
issue.setProperty("example_item_entity", entityId);
|
issue.setProperty("example_item_entity", entityId);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -13,25 +36,22 @@ import org.wikidata.wdtk.datamodel.interfaces.Reference;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
|
|
||||||
|
|
||||||
public class RestrictedPositionScrutinizer extends StatementScrutinizer {
|
public class RestrictedPositionScrutinizer extends StatementScrutinizer {
|
||||||
|
|
||||||
protected enum SnakPosition {
|
protected enum SnakPosition {
|
||||||
MAINSNAK,
|
MAINSNAK, QUALIFIER, REFERENCE
|
||||||
QUALIFIER,
|
|
||||||
REFERENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<PropertyIdValue, SnakPosition> _restrictedPids;
|
private Map<PropertyIdValue, SnakPosition> _restrictedPids;
|
||||||
private Set<PropertyIdValue> _unrestrictedPids;
|
private Set<PropertyIdValue> _unrestrictedPids;
|
||||||
|
|
||||||
public RestrictedPositionScrutinizer() {
|
public RestrictedPositionScrutinizer() {
|
||||||
_restrictedPids = new HashMap<>();
|
_restrictedPids = new HashMap<>();
|
||||||
_unrestrictedPids = new HashSet<>();
|
_unrestrictedPids = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
SnakPosition positionRestriction(PropertyIdValue pid) {
|
SnakPosition positionRestriction(PropertyIdValue pid) {
|
||||||
if(_unrestrictedPids.contains(pid)) {
|
if (_unrestrictedPids.contains(pid)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
SnakPosition restriction = _restrictedPids.get(pid);
|
SnakPosition restriction = _restrictedPids.get(pid);
|
||||||
@ -45,7 +65,7 @@ public class RestrictedPositionScrutinizer extends StatementScrutinizer {
|
|||||||
} else if (_fetcher.isForReferencesOnly(pid)) {
|
} else if (_fetcher.isForReferencesOnly(pid)) {
|
||||||
restriction = SnakPosition.REFERENCE;
|
restriction = SnakPosition.REFERENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache these results:
|
// Cache these results:
|
||||||
if (restriction != null) {
|
if (restriction != null) {
|
||||||
_restrictedPids.put(pid, restriction);
|
_restrictedPids.put(pid, restriction);
|
||||||
@ -55,39 +75,37 @@ public class RestrictedPositionScrutinizer extends StatementScrutinizer {
|
|||||||
return restriction;
|
return restriction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
||||||
// Skip the main snak
|
// Skip the main snak
|
||||||
scrutinize(statement.getClaim().getMainSnak(), entityId, SnakPosition.MAINSNAK, added);
|
scrutinize(statement.getClaim().getMainSnak(), entityId, SnakPosition.MAINSNAK, added);
|
||||||
|
|
||||||
// Qualifiers
|
// Qualifiers
|
||||||
scrutinizeSnakSet(statement.getClaim().getAllQualifiers(), entityId, SnakPosition.QUALIFIER, added);
|
scrutinizeSnakSet(statement.getClaim().getAllQualifiers(), entityId, SnakPosition.QUALIFIER, added);
|
||||||
|
|
||||||
// References
|
// References
|
||||||
for(Reference ref : statement.getReferences()) {
|
for (Reference ref : statement.getReferences()) {
|
||||||
scrutinizeSnakSet(ref.getAllSnaks(), entityId, SnakPosition.REFERENCE, added);
|
scrutinizeSnakSet(ref.getAllSnaks(), entityId, SnakPosition.REFERENCE, added);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void scrutinizeSnakSet(Iterator<Snak> snaks, EntityIdValue entityId, SnakPosition position, boolean added) {
|
protected void scrutinizeSnakSet(Iterator<Snak> snaks, EntityIdValue entityId, SnakPosition position,
|
||||||
while(snaks.hasNext()) {
|
boolean added) {
|
||||||
|
while (snaks.hasNext()) {
|
||||||
Snak snak = snaks.next();
|
Snak snak = snaks.next();
|
||||||
scrutinize(snak, entityId, position, added);
|
scrutinize(snak, entityId, position, added);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scrutinize(Snak snak, EntityIdValue entityId, SnakPosition position, boolean added) {
|
public void scrutinize(Snak snak, EntityIdValue entityId, SnakPosition position, boolean added) {
|
||||||
SnakPosition restriction = positionRestriction(snak.getPropertyId());
|
SnakPosition restriction = positionRestriction(snak.getPropertyId());
|
||||||
if (restriction != null && position != restriction) {
|
if (restriction != null && position != restriction) {
|
||||||
String positionStr = position.toString().toLowerCase();
|
String positionStr = position.toString().toLowerCase();
|
||||||
String restrictionStr = restriction.toString().toLowerCase();
|
String restrictionStr = restriction.toString().toLowerCase();
|
||||||
|
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning("property-restricted-to-" + restrictionStr + "-found-in-" + positionStr,
|
||||||
"property-restricted-to-"+restrictionStr+"-found-in-"+positionStr,
|
snak.getPropertyId().getId(), QAWarning.Severity.IMPORTANT, 1);
|
||||||
snak.getPropertyId().getId(),
|
|
||||||
QAWarning.Severity.IMPORTANT,
|
|
||||||
1);
|
|
||||||
issue.setProperty("property_entity", snak.getPropertyId());
|
issue.setProperty("property_entity", snak.getPropertyId());
|
||||||
addIssue(issue);
|
addIssue(issue);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.openrefine.wikidata.qa.QAWarning;
|
import org.openrefine.wikidata.qa.QAWarning;
|
||||||
@ -5,22 +28,20 @@ import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scrutinizer that checks for self-referential statements.
|
* A scrutinizer that checks for self-referential statements. These statements
|
||||||
* These statements are flagged by Wikibase as suspicious.
|
* are flagged by Wikibase as suspicious.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SelfReferentialScrutinizer extends SnakScrutinizer {
|
public class SelfReferentialScrutinizer extends SnakScrutinizer {
|
||||||
|
|
||||||
public static final String type = "self-referential-statements";
|
public static final String type = "self-referential-statements";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(Snak snak, EntityIdValue entityId, boolean added) {
|
public void scrutinize(Snak snak, EntityIdValue entityId, boolean added) {
|
||||||
if (entityId.equals(snak.getValue())) {
|
if (entityId.equals(snak.getValue())) {
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(type, null, QAWarning.Severity.WARNING, 1);
|
||||||
type, null,
|
|
||||||
QAWarning.Severity.WARNING, 1);
|
|
||||||
issue.setProperty("example_entity", entityId);
|
issue.setProperty("example_entity", entityId);
|
||||||
addIssue(issue);
|
addIssue(issue);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -9,27 +32,25 @@ import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For now this scrutinizer only checks for uniqueness at
|
* For now this scrutinizer only checks for uniqueness at the item level (it
|
||||||
* the item level (it ignores qualifiers and references).
|
* ignores qualifiers and references).
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SingleValueScrutinizer extends ItemUpdateScrutinizer {
|
public class SingleValueScrutinizer extends ItemUpdateScrutinizer {
|
||||||
|
|
||||||
public static final String type = "single-valued-property-added-more-than-once";
|
public static final String type = "single-valued-property-added-more-than-once";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(ItemUpdate update) {
|
public void scrutinize(ItemUpdate update) {
|
||||||
Set<PropertyIdValue> seenSingleProperties = new HashSet<>();
|
Set<PropertyIdValue> seenSingleProperties = new HashSet<>();
|
||||||
|
|
||||||
for(Statement statement : update.getAddedStatements()) {
|
for (Statement statement : update.getAddedStatements()) {
|
||||||
PropertyIdValue pid = statement.getClaim().getMainSnak().getPropertyId();
|
PropertyIdValue pid = statement.getClaim().getMainSnak().getPropertyId();
|
||||||
if (seenSingleProperties.contains(pid)) {
|
if (seenSingleProperties.contains(pid)) {
|
||||||
|
|
||||||
QAWarning issue = new QAWarning(
|
QAWarning issue = new QAWarning(type, pid.getId(), QAWarning.Severity.WARNING, 1);
|
||||||
type, pid.getId(),
|
|
||||||
QAWarning.Severity.WARNING, 1);
|
|
||||||
issue.setProperty("property_entity", pid);
|
issue.setProperty("property_entity", pid);
|
||||||
issue.setProperty("example_entity", update.getItemId());
|
issue.setProperty("example_entity", update.getItemId());
|
||||||
addIssue(issue);
|
addIssue(issue);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -8,38 +31,42 @@ import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scrutinizer that inspects snaks individually, no matter whether they
|
* A scrutinizer that inspects snaks individually, no matter whether they appear
|
||||||
* appear as main snaks, qualifiers or references.
|
* as main snaks, qualifiers or references.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class SnakScrutinizer extends StatementScrutinizer {
|
public abstract class SnakScrutinizer extends StatementScrutinizer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the method that subclasses should override to implement their checks.
|
* This is the method that subclasses should override to implement their checks.
|
||||||
* @param snak: the snak to inspect
|
*
|
||||||
* @param entityId: the item on which it is going to (dis)appear
|
* @param snak:
|
||||||
* @param added: whether this snak is going to be added or deleted
|
* the snak to inspect
|
||||||
|
* @param entityId:
|
||||||
|
* the item on which it is going to (dis)appear
|
||||||
|
* @param added:
|
||||||
|
* whether this snak is going to be added or deleted
|
||||||
*/
|
*/
|
||||||
public abstract void scrutinize(Snak snak, EntityIdValue entityId, boolean added);
|
public abstract void scrutinize(Snak snak, EntityIdValue entityId, boolean added);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
||||||
// Main snak
|
// Main snak
|
||||||
scrutinize(statement.getClaim().getMainSnak(), entityId, added);
|
scrutinize(statement.getClaim().getMainSnak(), entityId, added);
|
||||||
|
|
||||||
// Qualifiers
|
// Qualifiers
|
||||||
scrutinizeSnakSet(statement.getClaim().getAllQualifiers(), entityId, added);
|
scrutinizeSnakSet(statement.getClaim().getAllQualifiers(), entityId, added);
|
||||||
|
|
||||||
// References
|
// References
|
||||||
for(Reference ref : statement.getReferences()) {
|
for (Reference ref : statement.getReferences()) {
|
||||||
scrutinizeSnakSet(ref.getAllSnaks(), entityId, added);
|
scrutinizeSnakSet(ref.getAllSnaks(), entityId, added);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void scrutinizeSnakSet(Iterator<Snak> snaks, EntityIdValue entityId, boolean added) {
|
protected void scrutinizeSnakSet(Iterator<Snak> snaks, EntityIdValue entityId, boolean added) {
|
||||||
while(snaks.hasNext()) {
|
while (snaks.hasNext()) {
|
||||||
Snak snak = snaks.next();
|
Snak snak = snaks.next();
|
||||||
scrutinize(snak, entityId, added);
|
scrutinize(snak, entityId, added);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
@ -9,7 +32,7 @@ public abstract class StatementScrutinizer extends ItemUpdateScrutinizer {
|
|||||||
@Override
|
@Override
|
||||||
public void scrutinize(ItemUpdate update) {
|
public void scrutinize(ItemUpdate update) {
|
||||||
EntityIdValue currentEntityId = update.getItemId();
|
EntityIdValue currentEntityId = update.getItemId();
|
||||||
for(Statement statement : update.getAddedStatements()) {
|
for (Statement statement : update.getAddedStatements()) {
|
||||||
scrutinize(statement, currentEntityId, true);
|
scrutinize(statement, currentEntityId, true);
|
||||||
}
|
}
|
||||||
for (Statement statement : update.getDeletedStatements()) {
|
for (Statement statement : update.getDeletedStatements()) {
|
||||||
@ -18,11 +41,15 @@ public abstract class StatementScrutinizer extends ItemUpdateScrutinizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method that should be overridden by subclasses, implementing
|
* The method that should be overridden by subclasses, implementing the checks
|
||||||
* the checks on one statement
|
* on one statement
|
||||||
* @param statement: the statement to scrutinize
|
*
|
||||||
* @param entityId: the id of the entity on which this statement is made or removed
|
* @param statement:
|
||||||
* @param added: whether this statement was added or deleted
|
* the statement to scrutinize
|
||||||
|
* @param entityId:
|
||||||
|
* the id of the entity on which this statement is made or removed
|
||||||
|
* @param added:
|
||||||
|
* whether this statement was added or deleted
|
||||||
*/
|
*/
|
||||||
public abstract void scrutinize(Statement statement, EntityIdValue entityId, boolean added);
|
public abstract void scrutinize(Statement statement, EntityIdValue entityId, boolean added);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
||||||
@ -6,16 +29,16 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
|||||||
/**
|
/**
|
||||||
* A scrutinizer checking for unsourced statements
|
* A scrutinizer checking for unsourced statements
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class UnsourcedScrutinizer extends StatementScrutinizer {
|
public class UnsourcedScrutinizer extends StatementScrutinizer {
|
||||||
|
|
||||||
public static final String type = "unsourced-statements";
|
public static final String type = "unsourced-statements";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
|
||||||
if(statement.getReferences().isEmpty() && added) {
|
if (statement.getReferences().isEmpty() && added) {
|
||||||
warning(type);
|
warning(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
@ -8,22 +31,23 @@ import org.wikidata.wdtk.datamodel.interfaces.Value;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A scrutinizer that inspects the values of snaks and terms
|
* A scrutinizer that inspects the values of snaks and terms
|
||||||
* @author antonin
|
*
|
||||||
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class ValueScrutinizer extends SnakScrutinizer {
|
public abstract class ValueScrutinizer extends SnakScrutinizer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scrutinize(ItemUpdate update) {
|
public void scrutinize(ItemUpdate update) {
|
||||||
super.scrutinize(update);
|
super.scrutinize(update);
|
||||||
|
|
||||||
for(MonolingualTextValue label : update.getLabels()) {
|
for (MonolingualTextValue label : update.getLabels()) {
|
||||||
scrutinize(label);
|
scrutinize(label);
|
||||||
}
|
}
|
||||||
for(MonolingualTextValue alias : update.getAliases()) {
|
for (MonolingualTextValue alias : update.getAliases()) {
|
||||||
scrutinize(alias);
|
scrutinize(alias);
|
||||||
}
|
}
|
||||||
for(MonolingualTextValue description : update.getDescriptions()) {
|
for (MonolingualTextValue description : update.getDescriptions()) {
|
||||||
scrutinize(description);
|
scrutinize(description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -17,20 +40,20 @@ import org.wikidata.wdtk.datamodel.interfaces.Value;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WhitespaceScrutinizer extends ValueScrutinizer {
|
public class WhitespaceScrutinizer extends ValueScrutinizer {
|
||||||
|
|
||||||
private Map<String,Pattern> _issuesMap;
|
private Map<String, Pattern> _issuesMap;
|
||||||
|
|
||||||
public static final String leadingWhitespaceType = "leading-whitespace";
|
public static final String leadingWhitespaceType = "leading-whitespace";
|
||||||
public static final String trailingWhitespaceType = "trailing-whitespace";
|
public static final String trailingWhitespaceType = "trailing-whitespace";
|
||||||
public static final String duplicateWhitespaceType = "duplicate-whitespace";
|
public static final String duplicateWhitespaceType = "duplicate-whitespace";
|
||||||
public static final String nonPrintableCharsType = "non-printable-characters";
|
public static final String nonPrintableCharsType = "non-printable-characters";
|
||||||
|
|
||||||
public WhitespaceScrutinizer() {
|
public WhitespaceScrutinizer() {
|
||||||
_issuesMap = new HashMap<>();
|
_issuesMap = new HashMap<>();
|
||||||
_issuesMap.put(leadingWhitespaceType, Pattern.compile("^\\s"));
|
_issuesMap.put(leadingWhitespaceType, Pattern.compile("^\\s"));
|
||||||
_issuesMap.put(trailingWhitespaceType, Pattern.compile("\\s$"));
|
_issuesMap.put(trailingWhitespaceType, Pattern.compile("\\s$"));
|
||||||
_issuesMap.put(duplicateWhitespaceType, Pattern.compile("\\s\\s"));
|
_issuesMap.put(duplicateWhitespaceType, Pattern.compile("\\s\\s"));
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/14565934/regular-expression-to-remove-all-non-printable-characters
|
// https://stackoverflow.com/questions/14565934/regular-expression-to-remove-all-non-printable-characters
|
||||||
_issuesMap.put(nonPrintableCharsType, Pattern.compile("[\\x00\\x03\\x08\\x0B\\x0C\\x0E-\\x1F]"));
|
_issuesMap.put(nonPrintableCharsType, Pattern.compile("[\\x00\\x03\\x08\\x0B\\x0C\\x0E-\\x1F]"));
|
||||||
}
|
}
|
||||||
@ -38,21 +61,21 @@ public class WhitespaceScrutinizer extends ValueScrutinizer {
|
|||||||
@Override
|
@Override
|
||||||
public void scrutinize(Value value) {
|
public void scrutinize(Value value) {
|
||||||
String str = null;
|
String str = null;
|
||||||
if(MonolingualTextValue.class.isInstance(value)) {
|
if (MonolingualTextValue.class.isInstance(value)) {
|
||||||
str = ((MonolingualTextValue)value).getText();
|
str = ((MonolingualTextValue) value).getText();
|
||||||
} else if (StringValue.class.isInstance(value)) {
|
} else if (StringValue.class.isInstance(value)) {
|
||||||
str = ((StringValue)value).getString();
|
str = ((StringValue) value).getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str != null) {
|
if (str != null) {
|
||||||
for(Entry<String,Pattern> entry : _issuesMap.entrySet()) {
|
for (Entry<String, Pattern> entry : _issuesMap.entrySet()) {
|
||||||
if(entry.getValue().matcher(str).find()) {
|
if (entry.getValue().matcher(str).find()) {
|
||||||
emitWarning(entry.getKey(), str);
|
emitWarning(entry.getKey(), str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void emitWarning(String type, String example) {
|
private void emitWarning(String type, String example) {
|
||||||
QAWarning warning = new QAWarning(type, null, QAWarning.Severity.WARNING, 1);
|
QAWarning warning = new QAWarning(type, null, QAWarning.Severity.WARNING, 1);
|
||||||
warning.setProperty("example_string", example);
|
warning.setProperty("example_string", example);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
@ -10,39 +33,36 @@ import com.google.refine.model.ColumnModel;
|
|||||||
import com.google.refine.model.Row;
|
import com.google.refine.model.Row;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class holding all the necessary information about
|
* A class holding all the necessary information about the context in which a
|
||||||
* the context in which a schema expression is evaluated.
|
* schema expression is evaluated.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ExpressionContext {
|
public class ExpressionContext {
|
||||||
|
|
||||||
private String baseIRI;
|
private String baseIRI;
|
||||||
private int rowId;
|
private int rowId;
|
||||||
private Row row;
|
private Row row;
|
||||||
private ColumnModel columnModel;
|
private ColumnModel columnModel;
|
||||||
private QAWarningStore warningStore;
|
private QAWarningStore warningStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an expression context to evaluate a schema on a row
|
* Builds an expression context to evaluate a schema on a row
|
||||||
|
*
|
||||||
* @param baseIRI
|
* @param baseIRI
|
||||||
* the siteIRI of the schema
|
* the siteIRI of the schema
|
||||||
* @param rowId
|
* @param rowId
|
||||||
* the id of the row currently visited
|
* the id of the row currently visited
|
||||||
* @param row
|
* @param row
|
||||||
* the row itself
|
* the row itself
|
||||||
* @param columnModel
|
* @param columnModel
|
||||||
* lets us access cells by column name
|
* lets us access cells by column name
|
||||||
* @param warningStore
|
* @param warningStore
|
||||||
* where to store the issues encountered when
|
* where to store the issues encountered when evaluating (can be set
|
||||||
* evaluating (can be set to null if these issues should be ignored)
|
* to null if these issues should be ignored)
|
||||||
*/
|
*/
|
||||||
public ExpressionContext(
|
public ExpressionContext(String baseIRI, int rowId, Row row, ColumnModel columnModel, QAWarningStore warningStore) {
|
||||||
String baseIRI,
|
|
||||||
int rowId,
|
|
||||||
Row row,
|
|
||||||
ColumnModel columnModel,
|
|
||||||
QAWarningStore warningStore) {
|
|
||||||
Validate.notNull(baseIRI);
|
Validate.notNull(baseIRI);
|
||||||
this.baseIRI = baseIRI;
|
this.baseIRI = baseIRI;
|
||||||
this.rowId = rowId;
|
this.rowId = rowId;
|
||||||
@ -52,18 +72,18 @@ public class ExpressionContext {
|
|||||||
this.columnModel = columnModel;
|
this.columnModel = columnModel;
|
||||||
this.warningStore = warningStore;
|
this.warningStore = warningStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBaseIRI() {
|
public String getBaseIRI() {
|
||||||
return baseIRI;
|
return baseIRI;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a cell in the current row, by column name.
|
* Retrieves a cell in the current row, by column name. If the column does not
|
||||||
* If the column does not exist, null is returned.
|
* exist, null is returned.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* the name of the column to retrieve the cell from
|
* the name of the column to retrieve the cell from
|
||||||
* @return
|
* @return the cell
|
||||||
* the cell
|
|
||||||
*/
|
*/
|
||||||
public Cell getCellByName(String name) {
|
public Cell getCellByName(String name) {
|
||||||
Column column = columnModel.getColumnByName(name);
|
Column column = columnModel.getColumnByName(name);
|
||||||
@ -74,11 +94,11 @@ public class ExpressionContext {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRowId() {
|
public int getRowId() {
|
||||||
return rowId;
|
return rowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addWarning(QAWarning warning) {
|
public void addWarning(QAWarning warning) {
|
||||||
if (warningStore != null) {
|
if (warningStore != null) {
|
||||||
warningStore.addWarning(warning);
|
warningStore.addWarning(warning);
|
||||||
|
@ -1,12 +1,35 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.ParsePosition;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.ParsePosition;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
|
|
||||||
import org.jsoup.helper.Validate;
|
import org.jsoup.helper.Validate;
|
||||||
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
||||||
@ -19,8 +42,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constant for a time value, accepting a number of formats
|
* A constant for a time value, accepting a number of formats which determine
|
||||||
* which determine the precision of the parsed value.
|
* the precision of the parsed value.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
@ -28,60 +51,57 @@ import com.google.common.collect.ImmutableMap;
|
|||||||
public class WbDateConstant implements WbExpression<TimeValue> {
|
public class WbDateConstant implements WbExpression<TimeValue> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of formats accepted by the parser. Each format is associated
|
* Map of formats accepted by the parser. Each format is associated to the time
|
||||||
* to the time precision it induces (an integer according to Wikibase's data model).
|
* precision it induces (an integer according to Wikibase's data model).
|
||||||
*/
|
*/
|
||||||
public static Map<SimpleDateFormat,Integer> acceptedFormats = ImmutableMap.<SimpleDateFormat,Integer>builder()
|
public static Map<SimpleDateFormat, Integer> acceptedFormats = ImmutableMap.<SimpleDateFormat, Integer> builder()
|
||||||
.put(new SimpleDateFormat("yyyy"), 9)
|
.put(new SimpleDateFormat("yyyy"), 9).put(new SimpleDateFormat("yyyy-MM"), 10)
|
||||||
.put(new SimpleDateFormat("yyyy-MM"), 10)
|
.put(new SimpleDateFormat("yyyy-MM-dd"), 11).put(new SimpleDateFormat("yyyy-MM-dd'T'HH"), 12)
|
||||||
.put(new SimpleDateFormat("yyyy-MM-dd"), 11)
|
.put(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm"), 13)
|
||||||
.put(new SimpleDateFormat("yyyy-MM-dd'T'HH"), 12)
|
.put(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"), 14).build();
|
||||||
.put(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm"), 13)
|
|
||||||
.put(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"), 14)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private TimeValue parsed;
|
private TimeValue parsed;
|
||||||
private String origDatestamp;
|
private String origDatestamp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor. Used for deserialization from JSON.
|
* Constructor. Used for deserialization from JSON. The object will be
|
||||||
* The object will be constructed even if the time cannot
|
* constructed even if the time cannot be parsed (it will evaluate to null) in
|
||||||
* be parsed (it will evaluate to null) in {@link evaluate}.
|
* {@link evaluate}.
|
||||||
*
|
*
|
||||||
* @param origDatestamp
|
* @param origDatestamp
|
||||||
* the date value as a string
|
* the date value as a string
|
||||||
*/
|
*/
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbDateConstant(
|
public WbDateConstant(@JsonProperty("value") String origDatestamp) {
|
||||||
@JsonProperty("value") String origDatestamp) {
|
|
||||||
Validate.notNull(origDatestamp);
|
Validate.notNull(origDatestamp);
|
||||||
this.setOrigDatestamp(origDatestamp);
|
this.setOrigDatestamp(origDatestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimeValue evaluate(ExpressionContext ctxt)
|
public TimeValue evaluate(ExpressionContext ctxt)
|
||||||
throws SkipSchemaExpressionException {
|
throws SkipSchemaExpressionException {
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a timestamp into a Wikibase {@link TimeValue}. The
|
* Parses a timestamp into a Wikibase {@link TimeValue}. The precision is
|
||||||
* precision is automatically inferred from the format.
|
* automatically inferred from the format.
|
||||||
*
|
*
|
||||||
* @param datestamp
|
* @param datestamp
|
||||||
* the time to parse
|
* the time to parse
|
||||||
* @return
|
* @return
|
||||||
* @throws ParseException
|
* @throws ParseException
|
||||||
* if the time cannot be parsed
|
* if the time cannot be parsed
|
||||||
*/
|
*/
|
||||||
public static TimeValue parse(String datestamp) throws ParseException {
|
public static TimeValue parse(String datestamp)
|
||||||
|
throws ParseException {
|
||||||
Date date = null;
|
Date date = null;
|
||||||
int precision = 9; // default precision (will be overridden)
|
int precision = 9; // default precision (will be overridden)
|
||||||
for(Entry<SimpleDateFormat,Integer> entry : acceptedFormats.entrySet()) {
|
for (Entry<SimpleDateFormat, Integer> entry : acceptedFormats.entrySet()) {
|
||||||
ParsePosition position = new ParsePosition(0);
|
ParsePosition position = new ParsePosition(0);
|
||||||
String trimmedDatestamp = datestamp.trim();
|
String trimmedDatestamp = datestamp.trim();
|
||||||
date = entry.getKey().parse(trimmedDatestamp, position);
|
date = entry.getKey().parse(trimmedDatestamp, position);
|
||||||
|
|
||||||
// Ignore parses which failed or do not consume all the input
|
// Ignore parses which failed or do not consume all the input
|
||||||
if (date != null && position.getIndex() == trimmedDatestamp.length()) {
|
if (date != null && position.getIndex() == trimmedDatestamp.length()) {
|
||||||
precision = entry.getValue();
|
precision = entry.getValue();
|
||||||
@ -94,21 +114,16 @@ public class WbDateConstant implements WbExpression<TimeValue> {
|
|||||||
Calendar calendar = Calendar.getInstance();
|
Calendar calendar = Calendar.getInstance();
|
||||||
calendar = Calendar.getInstance();
|
calendar = Calendar.getInstance();
|
||||||
calendar.setTime(date);
|
calendar.setTime(date);
|
||||||
return Datamodel.makeTimeValue(
|
return Datamodel.makeTimeValue(calendar.get(Calendar.YEAR), (byte) (calendar.get(Calendar.MONTH) + 1), // java
|
||||||
calendar.get(Calendar.YEAR),
|
// starts
|
||||||
(byte) (calendar.get(Calendar.MONTH)+1), // java starts at 0
|
// at
|
||||||
(byte) calendar.get(Calendar.DAY_OF_MONTH),
|
// 0
|
||||||
(byte) calendar.get(Calendar.HOUR_OF_DAY),
|
(byte) calendar.get(Calendar.DAY_OF_MONTH), (byte) calendar.get(Calendar.HOUR_OF_DAY),
|
||||||
(byte) calendar.get(Calendar.MINUTE),
|
(byte) calendar.get(Calendar.MINUTE), (byte) calendar.get(Calendar.SECOND), (byte) precision, 0, 1,
|
||||||
(byte) calendar.get(Calendar.SECOND),
|
calendar.getTimeZone().getRawOffset() / 3600000, TimeValue.CM_GREGORIAN_PRO);
|
||||||
(byte) precision,
|
}
|
||||||
0,
|
|
||||||
1,
|
|
||||||
calendar.getTimeZone().getRawOffset()/3600000,
|
|
||||||
TimeValue.CM_GREGORIAN_PRO);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the original datestamp
|
* @return the original datestamp
|
||||||
*/
|
*/
|
||||||
@ -120,21 +135,21 @@ public class WbDateConstant implements WbExpression<TimeValue> {
|
|||||||
private void setOrigDatestamp(String origDatestamp) {
|
private void setOrigDatestamp(String origDatestamp) {
|
||||||
this.origDatestamp = origDatestamp;
|
this.origDatestamp = origDatestamp;
|
||||||
try {
|
try {
|
||||||
this.parsed = parse(origDatestamp);
|
this.parsed = parse(origDatestamp);
|
||||||
} catch(ParseException e) {
|
} catch (ParseException e) {
|
||||||
throw new IllegalArgumentException("Invalid datestamp provided: "+origDatestamp);
|
throw new IllegalArgumentException("Invalid datestamp provided: " + origDatestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbDateConstant.class.isInstance(other)) {
|
if (other == null || !WbDateConstant.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbDateConstant otherConstant = (WbDateConstant)other;
|
WbDateConstant otherConstant = (WbDateConstant) other;
|
||||||
return origDatestamp.equals(otherConstant.getOrigDatestamp());
|
return origDatestamp.equals(otherConstant.getOrigDatestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return origDatestamp.hashCode();
|
return origDatestamp.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
@ -10,19 +33,19 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||||||
import com.google.refine.model.Cell;
|
import com.google.refine.model.Cell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression that represents a time value, extracted from a string.
|
* An expression that represents a time value, extracted from a string. A number
|
||||||
* A number of formats are recognized, see {@link WbDateConstant} for details.
|
* of formats are recognized, see {@link WbDateConstant} for details.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WbDateVariable extends WbVariableExpr<TimeValue> {
|
public class WbDateVariable extends WbVariableExpr<TimeValue> {
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbDateVariable() {
|
public WbDateVariable() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public WbDateVariable(String columnName) {
|
public WbDateVariable(String columnName) {
|
||||||
setColumnName(columnName);
|
setColumnName(columnName);
|
||||||
}
|
}
|
||||||
@ -37,7 +60,7 @@ public class WbDateVariable extends WbVariableExpr<TimeValue> {
|
|||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return equalAsVariables(other, WbDateVariable.class);
|
return equalAsVariables(other, WbDateVariable.class);
|
||||||
|
@ -1,40 +1,60 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
|
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base interface for all expressions, which evaluate to a
|
* The base interface for all expressions, which evaluate to a particular type T
|
||||||
* particular type T in an ExpressionContext.
|
* in an ExpressionContext.
|
||||||
*/
|
*/
|
||||||
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
|
||||||
include=JsonTypeInfo.As.PROPERTY,
|
@JsonSubTypes({ @Type(value = WbStringConstant.class, name = "wbstringconstant"),
|
||||||
property="type")
|
@Type(value = WbStringVariable.class, name = "wbstringvariable"),
|
||||||
@JsonSubTypes({
|
@Type(value = WbLocationConstant.class, name = "wblocationconstant"),
|
||||||
@Type(value = WbStringConstant.class, name = "wbstringconstant"),
|
@Type(value = WbLocationVariable.class, name = "wblocationvariable"),
|
||||||
@Type(value = WbStringVariable.class, name = "wbstringvariable"),
|
@Type(value = WbItemConstant.class, name = "wbitemconstant"),
|
||||||
@Type(value = WbLocationConstant.class, name = "wblocationconstant"),
|
@Type(value = WbItemVariable.class, name = "wbitemvariable"),
|
||||||
@Type(value = WbLocationVariable.class, name = "wblocationvariable"),
|
@Type(value = WbLanguageConstant.class, name = "wblanguageconstant"),
|
||||||
@Type(value = WbItemConstant.class, name = "wbitemconstant"),
|
@Type(value = WbLanguageVariable.class, name = "wblanguagevariable"),
|
||||||
@Type(value = WbItemVariable.class, name = "wbitemvariable"),
|
@Type(value = WbDateConstant.class, name = "wbdateconstant"),
|
||||||
@Type(value = WbLanguageConstant.class, name = "wblanguageconstant"),
|
@Type(value = WbDateVariable.class, name = "wbdatevariable"),
|
||||||
@Type(value = WbLanguageVariable.class, name = "wblanguagevariable"),
|
@Type(value = WbMonolingualExpr.class, name = "wbmonolingualexpr"),
|
||||||
@Type(value = WbDateConstant.class, name = "wbdateconstant"),
|
@Type(value = WbPropConstant.class, name = "wbpropconstant"),
|
||||||
@Type(value = WbDateVariable.class, name = "wbdatevariable"),
|
@Type(value = WbLanguageConstant.class, name = "wblanguageconstant"),
|
||||||
@Type(value = WbMonolingualExpr.class, name = "wbmonolingualexpr"),
|
@Type(value = WbLanguageVariable.class, name = "wblanguagevariable"),
|
||||||
@Type(value = WbPropConstant.class, name = "wbpropconstant"),
|
@Type(value = WbQuantityExpr.class, name = "wbquantityexpr"), })
|
||||||
@Type(value = WbLanguageConstant.class, name = "wblanguageconstant"),
|
public interface WbExpression<T> {
|
||||||
@Type(value = WbLanguageVariable.class, name = "wblanguagevariable"),
|
|
||||||
@Type(value = WbQuantityExpr.class, name="wbquantityexpr"),
|
|
||||||
})
|
|
||||||
public interface WbExpression<T> {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the value expression in a given context,
|
* Evaluates the value expression in a given context, returns a Wikibase value
|
||||||
* returns a Wikibase value suitable to be the target of a claim.
|
* suitable to be the target of a claim.
|
||||||
*/
|
*/
|
||||||
public T evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException;
|
public T evaluate(ExpressionContext ctxt)
|
||||||
|
throws SkipSchemaExpressionException;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.jsoup.helper.Validate;
|
import org.jsoup.helper.Validate;
|
||||||
@ -8,18 +31,15 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an item that does not vary,
|
* Represents an item that does not vary, it is independent of the row.
|
||||||
* it is independent of the row.
|
|
||||||
*/
|
*/
|
||||||
public class WbItemConstant implements WbExpression<ItemIdValue> {
|
public class WbItemConstant implements WbExpression<ItemIdValue> {
|
||||||
|
|
||||||
private String qid;
|
private String qid;
|
||||||
private String label;
|
private String label;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbItemConstant(
|
public WbItemConstant(@JsonProperty("qid") String qid, @JsonProperty("label") String label) {
|
||||||
@JsonProperty("qid") String qid,
|
|
||||||
@JsonProperty("label") String label) {
|
|
||||||
Validate.notNull(qid);
|
Validate.notNull(qid);
|
||||||
this.qid = qid;
|
this.qid = qid;
|
||||||
Validate.notNull(label);
|
Validate.notNull(label);
|
||||||
@ -28,10 +48,7 @@ public class WbItemConstant implements WbExpression<ItemIdValue> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemIdValue evaluate(ExpressionContext ctxt) {
|
public ItemIdValue evaluate(ExpressionContext ctxt) {
|
||||||
return new SuggestedItemIdValue(
|
return new SuggestedItemIdValue(qid, ctxt.getBaseIRI(), label);
|
||||||
qid,
|
|
||||||
ctxt.getBaseIRI(),
|
|
||||||
label);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("qid")
|
@JsonProperty("qid")
|
||||||
@ -43,16 +60,16 @@ public class WbItemConstant implements WbExpression<ItemIdValue> {
|
|||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbItemConstant.class.isInstance(other)) {
|
if (other == null || !WbItemConstant.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbItemConstant otherConstant = (WbItemConstant)other;
|
WbItemConstant otherConstant = (WbItemConstant) other;
|
||||||
return (qid.equals(otherConstant.getQid()) && label.equals(otherConstant.getLabel()));
|
return (qid.equals(otherConstant.getQid()) && label.equals(otherConstant.getLabel()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return qid.hashCode() + label.hashCode();
|
return qid.hashCode() + label.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -17,51 +40,51 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The representation of an item document, which can contain
|
* The representation of an item document, which can contain variables both for
|
||||||
* variables both for its own id and in its contents.
|
* its own id and in its contents.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@JsonTypeInfo(use=JsonTypeInfo.Id.NONE)
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
|
||||||
public class WbItemDocumentExpr extends JacksonJsonizable implements WbExpression<ItemUpdate> {
|
public class WbItemDocumentExpr extends JacksonJsonizable implements WbExpression<ItemUpdate> {
|
||||||
|
|
||||||
private WbExpression<? extends ItemIdValue> subject;
|
private WbExpression<? extends ItemIdValue> subject;
|
||||||
private List<WbNameDescExpr> nameDescs;
|
private List<WbNameDescExpr> nameDescs;
|
||||||
private List<WbStatementGroupExpr> statementGroups;
|
private List<WbStatementGroupExpr> statementGroups;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbItemDocumentExpr(
|
public WbItemDocumentExpr(@JsonProperty("subject") WbExpression<? extends ItemIdValue> subjectExpr,
|
||||||
@JsonProperty("subject") WbExpression<? extends ItemIdValue> subjectExpr,
|
|
||||||
@JsonProperty("nameDescs") List<WbNameDescExpr> nameDescExprs,
|
@JsonProperty("nameDescs") List<WbNameDescExpr> nameDescExprs,
|
||||||
@JsonProperty("statementGroups") List<WbStatementGroupExpr> statementGroupExprs) {
|
@JsonProperty("statementGroups") List<WbStatementGroupExpr> statementGroupExprs) {
|
||||||
Validate.notNull(subjectExpr);
|
Validate.notNull(subjectExpr);
|
||||||
this.subject = subjectExpr;
|
this.subject = subjectExpr;
|
||||||
if(nameDescExprs == null) {
|
if (nameDescExprs == null) {
|
||||||
nameDescExprs = Collections.emptyList();
|
nameDescExprs = Collections.emptyList();
|
||||||
}
|
}
|
||||||
this.nameDescs = nameDescExprs;
|
this.nameDescs = nameDescExprs;
|
||||||
if(statementGroupExprs == null) {
|
if (statementGroupExprs == null) {
|
||||||
statementGroupExprs = Collections.emptyList();
|
statementGroupExprs = Collections.emptyList();
|
||||||
}
|
}
|
||||||
this.statementGroups = statementGroupExprs;
|
this.statementGroups = statementGroupExprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemUpdate evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException {
|
public ItemUpdate evaluate(ExpressionContext ctxt)
|
||||||
|
throws SkipSchemaExpressionException {
|
||||||
ItemIdValue subjectId = getSubject().evaluate(ctxt);
|
ItemIdValue subjectId = getSubject().evaluate(ctxt);
|
||||||
ItemUpdateBuilder update = new ItemUpdateBuilder(subjectId);
|
ItemUpdateBuilder update = new ItemUpdateBuilder(subjectId);
|
||||||
for(WbStatementGroupExpr expr : getStatementGroups()) {
|
for (WbStatementGroupExpr expr : getStatementGroups()) {
|
||||||
try {
|
try {
|
||||||
for(Statement s : expr.evaluate(ctxt, subjectId).getStatements()) {
|
for (Statement s : expr.evaluate(ctxt, subjectId).getStatements()) {
|
||||||
update.addStatement(s);
|
update.addStatement(s);
|
||||||
}
|
}
|
||||||
} catch (SkipSchemaExpressionException e) {
|
} catch (SkipSchemaExpressionException e) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(WbNameDescExpr expr : getNameDescs()) {
|
for (WbNameDescExpr expr : getNameDescs()) {
|
||||||
expr.contributeTo(update, ctxt);
|
expr.contributeTo(update, ctxt);
|
||||||
}
|
}
|
||||||
return update.build();
|
return update.build();
|
||||||
@ -81,18 +104,17 @@ public class WbItemDocumentExpr extends JacksonJsonizable implements WbExpressio
|
|||||||
public List<WbStatementGroupExpr> getStatementGroups() {
|
public List<WbStatementGroupExpr> getStatementGroups() {
|
||||||
return statementGroups;
|
return statementGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbItemDocumentExpr.class.isInstance(other)) {
|
if (other == null || !WbItemDocumentExpr.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbItemDocumentExpr otherExpr = (WbItemDocumentExpr)other;
|
WbItemDocumentExpr otherExpr = (WbItemDocumentExpr) other;
|
||||||
return subject.equals(otherExpr.getSubject()) &&
|
return subject.equals(otherExpr.getSubject()) && nameDescs.equals(otherExpr.getNameDescs())
|
||||||
nameDescs.equals(otherExpr.getNameDescs()) &&
|
&& statementGroups.equals(otherExpr.getStatementGroups());
|
||||||
statementGroups.equals(otherExpr.getStatementGroups());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return subject.hashCode() + nameDescs.hashCode() + statementGroups.hashCode();
|
return subject.hashCode() + nameDescs.hashCode() + statementGroups.hashCode();
|
||||||
|
@ -1,6 +1,28 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
||||||
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
||||||
@ -17,33 +39,33 @@ import com.google.refine.model.Recon.Judgment;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WbItemVariable extends WbVariableExpr<ItemIdValue> {
|
public class WbItemVariable extends WbVariableExpr<ItemIdValue> {
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbItemVariable() {
|
public WbItemVariable() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a variable and sets the column it is bound to. Mostly
|
* Constructs a variable and sets the column it is bound to. Mostly used as a
|
||||||
* used as a convenience method for testing.
|
* convenience method for testing.
|
||||||
*
|
*
|
||||||
* @param columnName
|
* @param columnName
|
||||||
* the name of the column the expression should draw its value from
|
* the name of the column the expression should draw its value from
|
||||||
*/
|
*/
|
||||||
public WbItemVariable(String columnName) {
|
public WbItemVariable(String columnName) {
|
||||||
setColumnName(columnName);
|
setColumnName(columnName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemIdValue fromCell(Cell cell, ExpressionContext ctxt) throws SkipSchemaExpressionException {
|
public ItemIdValue fromCell(Cell cell, ExpressionContext ctxt)
|
||||||
|
throws SkipSchemaExpressionException {
|
||||||
if (cell.recon != null
|
if (cell.recon != null
|
||||||
&& (Judgment.Matched.equals(cell.recon.judgment) ||
|
&& (Judgment.Matched.equals(cell.recon.judgment) || Judgment.New.equals(cell.recon.judgment))) {
|
||||||
Judgment.New.equals(cell.recon.judgment))) {
|
|
||||||
return new ReconItemIdValue(cell.recon, cell.value.toString());
|
return new ReconItemIdValue(cell.recon, cell.value.toString());
|
||||||
}
|
}
|
||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return equalAsVariables(other, WbItemVariable.class);
|
return equalAsVariables(other, WbItemVariable.class);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
@ -14,43 +37,41 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WbLanguageConstant implements WbExpression<String> {
|
public class WbLanguageConstant implements WbExpression<String> {
|
||||||
|
|
||||||
protected String _langId;
|
protected String _langId;
|
||||||
protected String _langLabel;
|
protected String _langLabel;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbLanguageConstant(
|
public WbLanguageConstant(@JsonProperty("id") String langId, @JsonProperty("label") String langLabel) {
|
||||||
@JsonProperty("id") String langId,
|
|
||||||
@JsonProperty("label") String langLabel) {
|
|
||||||
_langId = normalizeLanguageCode(langId);
|
_langId = normalizeLanguageCode(langId);
|
||||||
Validate.notNull(_langId, "A valid language code must be provided.");
|
Validate.notNull(_langId, "A valid language code must be provided.");
|
||||||
Validate.notNull(langLabel);
|
Validate.notNull(langLabel);
|
||||||
_langLabel = langLabel;
|
_langLabel = langLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that a language code is valid and returns its preferred
|
* Checks that a language code is valid and returns its preferred version
|
||||||
* version (converting deprecated language codes to their better values).
|
* (converting deprecated language codes to their better values).
|
||||||
*
|
*
|
||||||
* @param lang
|
* @param lang
|
||||||
* a Wikimedia language code
|
* a Wikimedia language code
|
||||||
* @return
|
* @return the normalized code, or null if the code is invalid.
|
||||||
* the normalized code, or null if the code is invalid.
|
|
||||||
*/
|
*/
|
||||||
public static String normalizeLanguageCode(String lang) {
|
public static String normalizeLanguageCode(String lang) {
|
||||||
try {
|
try {
|
||||||
WikimediaLanguageCodes.getLanguageCode(lang);
|
WikimediaLanguageCodes.getLanguageCode(lang);
|
||||||
return WikimediaLanguageCodes.fixLanguageCodeIfDeprecated(lang);
|
return WikimediaLanguageCodes.fixLanguageCodeIfDeprecated(lang);
|
||||||
} catch(IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException {
|
public String evaluate(ExpressionContext ctxt)
|
||||||
|
throws SkipSchemaExpressionException {
|
||||||
return _langId;
|
return _langId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the language code for this language
|
* @return the language code for this language
|
||||||
*/
|
*/
|
||||||
@ -58,7 +79,7 @@ public class WbLanguageConstant implements WbExpression<String> {
|
|||||||
public String getLang() {
|
public String getLang() {
|
||||||
return _langId;
|
return _langId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the name of the language in itself
|
* @return the name of the language in itself
|
||||||
*/
|
*/
|
||||||
@ -66,19 +87,19 @@ public class WbLanguageConstant implements WbExpression<String> {
|
|||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return _langLabel;
|
return _langLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbLanguageConstant.class.isInstance(other)) {
|
if (other == null || !WbLanguageConstant.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbLanguageConstant otherConstant = (WbLanguageConstant)other;
|
WbLanguageConstant otherConstant = (WbLanguageConstant) other;
|
||||||
return _langId.equals(otherConstant.getLang()) && _langLabel.equals(otherConstant.getLabel());
|
return _langId.equals(otherConstant.getLang()) && _langLabel.equals(otherConstant.getLabel());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return _langId.hashCode();
|
return _langId.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
||||||
@ -7,22 +30,22 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||||||
import com.google.refine.model.Cell;
|
import com.google.refine.model.Cell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A language variable generates a language code from a cell.
|
* A language variable generates a language code from a cell. It checks its
|
||||||
* It checks its values against a known list of valid language codes
|
* values against a known list of valid language codes and fixes on the fly the
|
||||||
* and fixes on the fly the deprecated ones (see {@link WbLanguageConstant}).
|
* deprecated ones (see {@link WbLanguageConstant}).
|
||||||
*/
|
*/
|
||||||
public class WbLanguageVariable extends WbVariableExpr<String> {
|
public class WbLanguageVariable extends WbVariableExpr<String> {
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbLanguageVariable() {
|
public WbLanguageVariable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a variable and sets the column it is bound to. Mostly
|
* Constructs a variable and sets the column it is bound to. Mostly used as a
|
||||||
* used as a convenience method for testing.
|
* convenience method for testing.
|
||||||
*
|
*
|
||||||
* @param columnName
|
* @param columnName
|
||||||
* the name of the column the expression should draw its value from
|
* the name of the column the expression should draw its value from
|
||||||
*/
|
*/
|
||||||
public WbLanguageVariable(String columnName) {
|
public WbLanguageVariable(String columnName) {
|
||||||
setColumnName(columnName);
|
setColumnName(columnName);
|
||||||
@ -40,7 +63,7 @@ public class WbLanguageVariable extends WbVariableExpr<String> {
|
|||||||
}
|
}
|
||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return equalAsVariables(other, WbLanguageVariable.class);
|
return equalAsVariables(other, WbLanguageVariable.class);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
@ -11,53 +34,52 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constant for a geographical location. The accepted format is lat,lng or lat/lng.
|
* A constant for a geographical location. The accepted format is lat,lng or
|
||||||
|
* lat/lng.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WbLocationConstant implements WbExpression<GlobeCoordinatesValue> {
|
public class WbLocationConstant implements WbExpression<GlobeCoordinatesValue> {
|
||||||
|
|
||||||
public static final double defaultPrecision = GlobeCoordinatesValue.PREC_TEN_MICRO_DEGREE;
|
public static final double defaultPrecision = GlobeCoordinatesValue.PREC_TEN_MICRO_DEGREE;
|
||||||
|
|
||||||
private String value;
|
private String value;
|
||||||
private GlobeCoordinatesValue parsed;
|
private GlobeCoordinatesValue parsed;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbLocationConstant(
|
public WbLocationConstant(@JsonProperty("value") String origValue) throws ParseException {
|
||||||
@JsonProperty("value") String origValue) throws ParseException {
|
|
||||||
this.value = origValue;
|
this.value = origValue;
|
||||||
Validate.notNull(origValue);
|
Validate.notNull(origValue);
|
||||||
this.parsed = parse(origValue);
|
this.parsed = parse(origValue);
|
||||||
Validate.notNull(this.parsed);
|
Validate.notNull(this.parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a string to a location.
|
* Parses a string to a location.
|
||||||
*
|
*
|
||||||
* @param expr
|
* @param expr
|
||||||
* the string to parse
|
* the string to parse
|
||||||
* @return
|
* @return the parsed location
|
||||||
* the parsed location
|
|
||||||
* @throws ParseException
|
* @throws ParseException
|
||||||
*/
|
*/
|
||||||
public static GlobeCoordinatesValue parse(String expr) throws ParseException {
|
public static GlobeCoordinatesValue parse(String expr)
|
||||||
|
throws ParseException {
|
||||||
double lat = 0;
|
double lat = 0;
|
||||||
double lng = 0;
|
double lng = 0;
|
||||||
double precision = defaultPrecision;
|
double precision = defaultPrecision;
|
||||||
String[] parts = expr.split("[,/]");
|
String[] parts = expr.split("[,/]");
|
||||||
if (parts.length >= 2 && parts.length <= 3) {
|
if (parts.length >= 2 && parts.length <= 3) {
|
||||||
try {
|
try {
|
||||||
lat = Double.parseDouble(parts[0]);
|
lat = Double.parseDouble(parts[0]);
|
||||||
lng = Double.parseDouble(parts[1]);
|
lng = Double.parseDouble(parts[1]);
|
||||||
if (parts.length == 3) {
|
if (parts.length == 3) {
|
||||||
precision = Double.parseDouble(parts[2]);
|
precision = Double.parseDouble(parts[2]);
|
||||||
}
|
}
|
||||||
return Datamodel.makeGlobeCoordinatesValue(lat, lng, precision,
|
return Datamodel.makeGlobeCoordinatesValue(lat, lng, precision, GlobeCoordinatesValue.GLOBE_EARTH);
|
||||||
GlobeCoordinatesValue.GLOBE_EARTH);
|
} catch (NumberFormatException e) {
|
||||||
} catch(NumberFormatException e) {
|
;
|
||||||
;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw new ParseException("Invalid globe coordinates", 0);
|
throw new ParseException("Invalid globe coordinates", 0);
|
||||||
}
|
}
|
||||||
@ -67,7 +89,7 @@ public class WbLocationConstant implements WbExpression<GlobeCoordinatesValue> {
|
|||||||
throws SkipSchemaExpressionException {
|
throws SkipSchemaExpressionException {
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the original value as a string.
|
* @return the original value as a string.
|
||||||
*/
|
*/
|
||||||
@ -75,16 +97,16 @@ public class WbLocationConstant implements WbExpression<GlobeCoordinatesValue> {
|
|||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbLocationConstant.class.isInstance(other)) {
|
if (other == null || !WbLocationConstant.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbLocationConstant otherConstant = (WbLocationConstant)other;
|
WbLocationConstant otherConstant = (WbLocationConstant) other;
|
||||||
return value.equals(otherConstant.getValue());
|
return value.equals(otherConstant.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return value.hashCode();
|
return value.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
@ -9,12 +32,11 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||||||
|
|
||||||
import com.google.refine.model.Cell;
|
import com.google.refine.model.Cell;
|
||||||
|
|
||||||
|
|
||||||
public class WbLocationVariable extends WbVariableExpr<GlobeCoordinatesValue> {
|
public class WbLocationVariable extends WbVariableExpr<GlobeCoordinatesValue> {
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbLocationVariable() {
|
public WbLocationVariable() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public WbLocationVariable(String columnName) {
|
public WbLocationVariable(String columnName) {
|
||||||
@ -31,7 +53,7 @@ public class WbLocationVariable extends WbVariableExpr<GlobeCoordinatesValue> {
|
|||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return equalAsVariables(other, WbLocationVariable.class);
|
return equalAsVariables(other, WbLocationVariable.class);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
@ -10,15 +33,13 @@ import org.wikidata.wdtk.datamodel.interfaces.StringValue;
|
|||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
|
||||||
public class WbMonolingualExpr implements WbExpression<MonolingualTextValue> {
|
public class WbMonolingualExpr implements WbExpression<MonolingualTextValue> {
|
||||||
|
|
||||||
private WbExpression<? extends String> languageExpr;
|
private WbExpression<? extends String> languageExpr;
|
||||||
private WbExpression<? extends StringValue> valueExpr;
|
private WbExpression<? extends StringValue> valueExpr;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbMonolingualExpr(
|
public WbMonolingualExpr(@JsonProperty("language") WbExpression<? extends String> languageExpr,
|
||||||
@JsonProperty("language") WbExpression<? extends String> languageExpr,
|
|
||||||
@JsonProperty("value") WbExpression<? extends StringValue> valueExpr) {
|
@JsonProperty("value") WbExpression<? extends StringValue> valueExpr) {
|
||||||
Validate.notNull(languageExpr);
|
Validate.notNull(languageExpr);
|
||||||
this.languageExpr = languageExpr;
|
this.languageExpr = languageExpr;
|
||||||
@ -33,13 +54,9 @@ public class WbMonolingualExpr implements WbExpression<MonolingualTextValue> {
|
|||||||
try {
|
try {
|
||||||
String lang = getLanguageExpr().evaluate(ctxt);
|
String lang = getLanguageExpr().evaluate(ctxt);
|
||||||
return Datamodel.makeMonolingualTextValue(text, lang);
|
return Datamodel.makeMonolingualTextValue(text, lang);
|
||||||
|
|
||||||
} catch(SkipSchemaExpressionException e) {
|
} catch (SkipSchemaExpressionException e) {
|
||||||
QAWarning warning = new QAWarning(
|
QAWarning warning = new QAWarning("monolingual-text-without-language", null, QAWarning.Severity.WARNING, 1);
|
||||||
"monolingual-text-without-language",
|
|
||||||
null,
|
|
||||||
QAWarning.Severity.WARNING,
|
|
||||||
1);
|
|
||||||
warning.setProperty("example_text", text);
|
warning.setProperty("example_text", text);
|
||||||
ctxt.addWarning(warning);
|
ctxt.addWarning(warning);
|
||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
@ -55,17 +72,16 @@ public class WbMonolingualExpr implements WbExpression<MonolingualTextValue> {
|
|||||||
public WbExpression<? extends StringValue> getValueExpr() {
|
public WbExpression<? extends StringValue> getValueExpr() {
|
||||||
return valueExpr;
|
return valueExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbMonolingualExpr.class.isInstance(other)) {
|
if (other == null || !WbMonolingualExpr.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbMonolingualExpr otherExpr = (WbMonolingualExpr)other;
|
WbMonolingualExpr otherExpr = (WbMonolingualExpr) other;
|
||||||
return languageExpr.equals(otherExpr.getLanguageExpr()) &&
|
return languageExpr.equals(otherExpr.getLanguageExpr()) && valueExpr.equals(otherExpr.getValueExpr());
|
||||||
valueExpr.equals(otherExpr.getValueExpr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return languageExpr.hashCode() + valueExpr.hashCode();
|
return languageExpr.hashCode() + valueExpr.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.jsoup.helper.Validate;
|
import org.jsoup.helper.Validate;
|
||||||
@ -10,56 +33,53 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression that represent a term (label, description or alias).
|
* An expression that represent a term (label, description or alias). The
|
||||||
* The structure is slightly different from other expressions because
|
* structure is slightly different from other expressions because we need to
|
||||||
* we need to call different methods on {@link ItemUpdateBuilder}.
|
* call different methods on {@link ItemUpdateBuilder}.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class WbNameDescExpr {
|
public class WbNameDescExpr {
|
||||||
|
|
||||||
enum NameDescrType {
|
enum NameDescrType {
|
||||||
LABEL,
|
LABEL, DESCRIPTION, ALIAS,
|
||||||
DESCRIPTION,
|
|
||||||
ALIAS,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private NameDescrType type;
|
private NameDescrType type;
|
||||||
private WbMonolingualExpr value;
|
private WbMonolingualExpr value;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbNameDescExpr(
|
public WbNameDescExpr(@JsonProperty("name_type") NameDescrType type,
|
||||||
@JsonProperty("name_type") NameDescrType type,
|
|
||||||
@JsonProperty("value") WbMonolingualExpr value) {
|
@JsonProperty("value") WbMonolingualExpr value) {
|
||||||
Validate.notNull(type);
|
Validate.notNull(type);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
Validate.notNull(value);
|
Validate.notNull(value);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the expression and adds the result to the item update.
|
* Evaluates the expression and adds the result to the item update.
|
||||||
*
|
*
|
||||||
* @param item
|
* @param item
|
||||||
* the item update where the term should be stored
|
* the item update where the term should be stored
|
||||||
* @param ctxt
|
* @param ctxt
|
||||||
* the evaluation context for the expression
|
* the evaluation context for the expression
|
||||||
*/
|
*/
|
||||||
public void contributeTo(ItemUpdateBuilder item, ExpressionContext ctxt) {
|
public void contributeTo(ItemUpdateBuilder item, ExpressionContext ctxt) {
|
||||||
try {
|
try {
|
||||||
MonolingualTextValue val = getValue().evaluate(ctxt);
|
MonolingualTextValue val = getValue().evaluate(ctxt);
|
||||||
switch (getType()) {
|
switch (getType()) {
|
||||||
case LABEL:
|
case LABEL:
|
||||||
item.addLabel(val);
|
item.addLabel(val);
|
||||||
break;
|
break;
|
||||||
case DESCRIPTION:
|
case DESCRIPTION:
|
||||||
item.addDescription(val);
|
item.addDescription(val);
|
||||||
break;
|
break;
|
||||||
case ALIAS:
|
case ALIAS:
|
||||||
item.addAlias(val);
|
item.addAlias(val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (SkipSchemaExpressionException e) {
|
} catch (SkipSchemaExpressionException e) {
|
||||||
return;
|
return;
|
||||||
@ -75,17 +95,16 @@ public class WbNameDescExpr {
|
|||||||
public WbMonolingualExpr getValue() {
|
public WbMonolingualExpr getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbNameDescExpr.class.isInstance(other)) {
|
if (other == null || !WbNameDescExpr.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbNameDescExpr otherExpr = (WbNameDescExpr)other;
|
WbNameDescExpr otherExpr = (WbNameDescExpr) other;
|
||||||
return type.equals(otherExpr.getType()) &&
|
return type.equals(otherExpr.getType()) && value.equals(otherExpr.getValue());
|
||||||
value.equals(otherExpr.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return type.hashCode() + value.hashCode();
|
return type.hashCode() + value.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.jsoup.helper.Validate;
|
import org.jsoup.helper.Validate;
|
||||||
@ -14,15 +37,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WbPropConstant implements WbExpression<PropertyIdValue> {
|
public class WbPropConstant implements WbExpression<PropertyIdValue> {
|
||||||
|
|
||||||
private String pid;
|
private String pid;
|
||||||
private String label;
|
private String label;
|
||||||
private String datatype;
|
private String datatype;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbPropConstant(
|
public WbPropConstant(@JsonProperty("pid") String pid, @JsonProperty("label") String label,
|
||||||
@JsonProperty("pid") String pid,
|
|
||||||
@JsonProperty("label") String label,
|
|
||||||
@JsonProperty("datatype") String datatype) {
|
@JsonProperty("datatype") String datatype) {
|
||||||
Validate.notNull(pid);
|
Validate.notNull(pid);
|
||||||
this.pid = pid;
|
this.pid = pid;
|
||||||
@ -35,7 +56,7 @@ public class WbPropConstant implements WbExpression<PropertyIdValue> {
|
|||||||
public PropertyIdValue evaluate(ExpressionContext ctxt) {
|
public PropertyIdValue evaluate(ExpressionContext ctxt) {
|
||||||
return new SuggestedPropertyIdValue(pid, ctxt.getBaseIRI(), label);
|
return new SuggestedPropertyIdValue(pid, ctxt.getBaseIRI(), label);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("pid")
|
@JsonProperty("pid")
|
||||||
public String getPid() {
|
public String getPid() {
|
||||||
return pid;
|
return pid;
|
||||||
@ -45,19 +66,20 @@ public class WbPropConstant implements WbExpression<PropertyIdValue> {
|
|||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("datatype")
|
@JsonProperty("datatype")
|
||||||
public String getDatatype() {
|
public String getDatatype() {
|
||||||
return datatype;
|
return datatype;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbPropConstant.class.isInstance(other)) {
|
if (other == null || !WbPropConstant.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbPropConstant otherConstant = (WbPropConstant)other;
|
WbPropConstant otherConstant = (WbPropConstant) other;
|
||||||
return pid.equals(otherConstant.getPid()) && label.equals(otherConstant.getLabel()) && datatype.equals(otherConstant.getDatatype());
|
return pid.equals(otherConstant.getPid()) && label.equals(otherConstant.getLabel())
|
||||||
|
&& datatype.equals(otherConstant.getDatatype());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -13,22 +36,21 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
public class WbQuantityExpr implements WbExpression<QuantityValue> {
|
public class WbQuantityExpr implements WbExpression<QuantityValue> {
|
||||||
|
|
||||||
private final WbExpression<? extends StringValue> amountExpr;
|
private final WbExpression<? extends StringValue> amountExpr;
|
||||||
private final WbExpression<? extends ItemIdValue> unitExpr;
|
private final WbExpression<? extends ItemIdValue> unitExpr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an expression for a quantity, which
|
* Creates an expression for a quantity, which contains two sub-expressions: one
|
||||||
* contains two sub-expressions: one for the amount (a string with
|
* for the amount (a string with a particular format) and one for the unit,
|
||||||
* a particular format) and one for the unit, which is optional.
|
* which is optional.
|
||||||
*
|
*
|
||||||
* Setting unitExpr to null will give quantities without units. Setting
|
* Setting unitExpr to null will give quantities without units. Setting it to a
|
||||||
* it to a non-null value will make the unit mandatory: if the unit expression
|
* non-null value will make the unit mandatory: if the unit expression fails to
|
||||||
* fails to evaluate, the whole quantity expression will fail too.
|
* evaluate, the whole quantity expression will fail too.
|
||||||
*/
|
*/
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbQuantityExpr(
|
public WbQuantityExpr(@JsonProperty("amount") WbExpression<? extends StringValue> amountExpr,
|
||||||
@JsonProperty("amount") WbExpression<? extends StringValue> amountExpr,
|
|
||||||
@JsonProperty("unit") WbExpression<? extends ItemIdValue> unitExpr) {
|
@JsonProperty("unit") WbExpression<? extends ItemIdValue> unitExpr) {
|
||||||
Validate.notNull(amountExpr);
|
Validate.notNull(amountExpr);
|
||||||
this.amountExpr = amountExpr;
|
this.amountExpr = amountExpr;
|
||||||
@ -40,22 +62,22 @@ public class WbQuantityExpr implements WbExpression<QuantityValue> {
|
|||||||
throws SkipSchemaExpressionException {
|
throws SkipSchemaExpressionException {
|
||||||
StringValue amount = getLanguageExpr().evaluate(ctxt);
|
StringValue amount = getLanguageExpr().evaluate(ctxt);
|
||||||
// we know the amount is nonnull, nonempty here
|
// we know the amount is nonnull, nonempty here
|
||||||
|
|
||||||
BigDecimal parsedAmount = null;
|
BigDecimal parsedAmount = null;
|
||||||
try {
|
try {
|
||||||
parsedAmount = new BigDecimal(amount.getString());
|
parsedAmount = new BigDecimal(amount.getString());
|
||||||
} catch(NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(getUnitExpr() != null) {
|
if (getUnitExpr() != null) {
|
||||||
ItemIdValue unit = getUnitExpr().evaluate(ctxt);
|
ItemIdValue unit = getUnitExpr().evaluate(ctxt);
|
||||||
return Datamodel.makeQuantityValue(parsedAmount, unit.getIri());
|
return Datamodel.makeQuantityValue(parsedAmount, unit.getIri());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Datamodel.makeQuantityValue(parsedAmount);
|
return Datamodel.makeQuantityValue(parsedAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("amount")
|
@JsonProperty("amount")
|
||||||
public WbExpression<? extends StringValue> getLanguageExpr() {
|
public WbExpression<? extends StringValue> getLanguageExpr() {
|
||||||
return amountExpr;
|
return amountExpr;
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -22,19 +45,20 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@JsonTypeInfo(use=JsonTypeInfo.Id.NONE)
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
|
||||||
public class WbReferenceExpr implements WbExpression<Reference> {
|
public class WbReferenceExpr implements WbExpression<Reference> {
|
||||||
|
|
||||||
private List<WbSnakExpr> snakExprs;
|
private List<WbSnakExpr> snakExprs;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbReferenceExpr(
|
public WbReferenceExpr(@JsonProperty("snaks") List<WbSnakExpr> snakExprs) {
|
||||||
@JsonProperty("snaks") List<WbSnakExpr> snakExprs) {
|
|
||||||
Validate.notNull(snakExprs);
|
Validate.notNull(snakExprs);
|
||||||
this.snakExprs = snakExprs;
|
this.snakExprs = snakExprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Reference evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException {
|
public Reference evaluate(ExpressionContext ctxt)
|
||||||
|
throws SkipSchemaExpressionException {
|
||||||
List<SnakGroup> snakGroups = new ArrayList<SnakGroup>();
|
List<SnakGroup> snakGroups = new ArrayList<SnakGroup>();
|
||||||
for (WbSnakExpr expr : getSnaks()) {
|
for (WbSnakExpr expr : getSnaks()) {
|
||||||
List<Snak> snakList = new ArrayList<Snak>(1);
|
List<Snak> snakList = new ArrayList<Snak>(1);
|
||||||
@ -45,7 +69,7 @@ public class WbReferenceExpr implements WbExpression<Reference> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! snakGroups.isEmpty()) {
|
if (!snakGroups.isEmpty()) {
|
||||||
return Datamodel.makeReference(snakGroups);
|
return Datamodel.makeReference(snakGroups);
|
||||||
} else {
|
} else {
|
||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
@ -59,13 +83,13 @@ public class WbReferenceExpr implements WbExpression<Reference> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WbReferenceExpr.class.isInstance(other)) {
|
if (other == null || !WbReferenceExpr.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbReferenceExpr otherExpr = (WbReferenceExpr)other;
|
WbReferenceExpr otherExpr = (WbReferenceExpr) other;
|
||||||
return snakExprs.equals(otherExpr.getSnaks());
|
return snakExprs.equals(otherExpr.getSnaks());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return snakExprs.hashCode();
|
return snakExprs.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.jsoup.helper.Validate;
|
import org.jsoup.helper.Validate;
|
||||||
@ -19,15 +42,14 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@JsonTypeInfo(use=JsonTypeInfo.Id.NONE)
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
|
||||||
public class WbSnakExpr implements WbExpression<Snak> {
|
public class WbSnakExpr implements WbExpression<Snak> {
|
||||||
|
|
||||||
private WbExpression<? extends PropertyIdValue> prop;
|
private WbExpression<? extends PropertyIdValue> prop;
|
||||||
private WbExpression<? extends Value> value;
|
private WbExpression<? extends Value> value;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbSnakExpr(
|
public WbSnakExpr(@JsonProperty("prop") WbExpression<? extends PropertyIdValue> propExpr,
|
||||||
@JsonProperty("prop") WbExpression<? extends PropertyIdValue> propExpr,
|
|
||||||
@JsonProperty("value") WbExpression<? extends Value> valueExpr) {
|
@JsonProperty("value") WbExpression<? extends Value> valueExpr) {
|
||||||
Validate.notNull(propExpr);
|
Validate.notNull(propExpr);
|
||||||
this.prop = propExpr;
|
this.prop = propExpr;
|
||||||
@ -36,7 +58,8 @@ public class WbSnakExpr implements WbExpression<Snak> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Snak evaluate(ExpressionContext ctxt) throws SkipSchemaExpressionException {
|
public Snak evaluate(ExpressionContext ctxt)
|
||||||
|
throws SkipSchemaExpressionException {
|
||||||
PropertyIdValue propertyId = getProp().evaluate(ctxt);
|
PropertyIdValue propertyId = getProp().evaluate(ctxt);
|
||||||
Value evaluatedValue = value.evaluate(ctxt);
|
Value evaluatedValue = value.evaluate(ctxt);
|
||||||
return Datamodel.makeValueSnak(propertyId, evaluatedValue);
|
return Datamodel.makeValueSnak(propertyId, evaluatedValue);
|
||||||
@ -51,7 +74,7 @@ public class WbSnakExpr implements WbExpression<Snak> {
|
|||||||
public WbExpression<? extends Value> getValue() {
|
public WbExpression<? extends Value> getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null || !WbSnakExpr.class.isInstance(other)) {
|
if (other == null || !WbSnakExpr.class.isInstance(other)) {
|
||||||
@ -60,7 +83,7 @@ public class WbSnakExpr implements WbExpression<Snak> {
|
|||||||
WbSnakExpr otherExpr = (WbSnakExpr) other;
|
WbSnakExpr otherExpr = (WbSnakExpr) other;
|
||||||
return prop.equals(otherExpr.getProp()) && value.equals(otherExpr.getValue());
|
return prop.equals(otherExpr.getProp()) && value.equals(otherExpr.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return prop.hashCode() + value.hashCode();
|
return prop.hashCode() + value.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -10,10 +33,10 @@ import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
|||||||
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Claim;
|
import org.wikidata.wdtk.datamodel.interfaces.Claim;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
||||||
|
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Reference;
|
import org.wikidata.wdtk.datamodel.interfaces.Reference;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
import org.wikidata.wdtk.datamodel.interfaces.Snak;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.SnakGroup;
|
import org.wikidata.wdtk.datamodel.interfaces.SnakGroup;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.StatementRank;
|
import org.wikidata.wdtk.datamodel.interfaces.StatementRank;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
||||||
@ -24,14 +47,13 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class WbStatementExpr {
|
public class WbStatementExpr {
|
||||||
|
|
||||||
private WbExpression<? extends Value> mainSnakValueExpr;
|
private WbExpression<? extends Value> mainSnakValueExpr;
|
||||||
private List<WbSnakExpr> qualifierExprs;
|
private List<WbSnakExpr> qualifierExprs;
|
||||||
private List<WbReferenceExpr> referenceExprs;
|
private List<WbReferenceExpr> referenceExprs;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbStatementExpr(
|
public WbStatementExpr(@JsonProperty("value") WbExpression<? extends Value> mainSnakValueExpr,
|
||||||
@JsonProperty("value") WbExpression<? extends Value> mainSnakValueExpr,
|
|
||||||
@JsonProperty("qualifiers") List<WbSnakExpr> qualifierExprs,
|
@JsonProperty("qualifiers") List<WbSnakExpr> qualifierExprs,
|
||||||
@JsonProperty("references") List<WbReferenceExpr> referenceExprs) {
|
@JsonProperty("references") List<WbReferenceExpr> referenceExprs) {
|
||||||
Validate.notNull(mainSnakValueExpr);
|
Validate.notNull(mainSnakValueExpr);
|
||||||
@ -45,7 +67,7 @@ public class WbStatementExpr {
|
|||||||
}
|
}
|
||||||
this.referenceExprs = referenceExprs;
|
this.referenceExprs = referenceExprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<SnakGroup> groupSnaks(List<Snak> snaks) {
|
public static List<SnakGroup> groupSnaks(List<Snak> snaks) {
|
||||||
List<SnakGroup> snakGroups = new ArrayList<SnakGroup>();
|
List<SnakGroup> snakGroups = new ArrayList<SnakGroup>();
|
||||||
for (Snak snak : snaks) {
|
for (Snak snak : snaks) {
|
||||||
@ -55,23 +77,19 @@ public class WbStatementExpr {
|
|||||||
}
|
}
|
||||||
return snakGroups;
|
return snakGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Statement evaluate(ExpressionContext ctxt, ItemIdValue subject, PropertyIdValue propertyId)
|
public Statement evaluate(ExpressionContext ctxt, ItemIdValue subject, PropertyIdValue propertyId)
|
||||||
throws SkipSchemaExpressionException {
|
throws SkipSchemaExpressionException {
|
||||||
Value mainSnakValue = getMainsnak().evaluate(ctxt);
|
Value mainSnakValue = getMainsnak().evaluate(ctxt);
|
||||||
Snak mainSnak = Datamodel.makeValueSnak(propertyId, mainSnakValue);
|
Snak mainSnak = Datamodel.makeValueSnak(propertyId, mainSnakValue);
|
||||||
|
|
||||||
// evaluate qualifiers
|
// evaluate qualifiers
|
||||||
List<Snak> qualifiers = new ArrayList<Snak>(getQualifiers().size());
|
List<Snak> qualifiers = new ArrayList<Snak>(getQualifiers().size());
|
||||||
for (WbSnakExpr qExpr : getQualifiers()) {
|
for (WbSnakExpr qExpr : getQualifiers()) {
|
||||||
try {
|
try {
|
||||||
qualifiers.add(qExpr.evaluate(ctxt));
|
qualifiers.add(qExpr.evaluate(ctxt));
|
||||||
} catch(SkipSchemaExpressionException e) {
|
} catch (SkipSchemaExpressionException e) {
|
||||||
QAWarning warning = new QAWarning(
|
QAWarning warning = new QAWarning("ignored-qualifiers", null, QAWarning.Severity.INFO, 1);
|
||||||
"ignored-qualifiers",
|
|
||||||
null,
|
|
||||||
QAWarning.Severity.INFO,
|
|
||||||
1);
|
|
||||||
warning.setProperty("example_entity", subject);
|
warning.setProperty("example_entity", subject);
|
||||||
warning.setProperty("example_property_entity", mainSnak.getPropertyId());
|
warning.setProperty("example_property_entity", mainSnak.getPropertyId());
|
||||||
ctxt.addWarning(warning);
|
ctxt.addWarning(warning);
|
||||||
@ -79,24 +97,20 @@ public class WbStatementExpr {
|
|||||||
}
|
}
|
||||||
List<SnakGroup> groupedQualifiers = groupSnaks(qualifiers);
|
List<SnakGroup> groupedQualifiers = groupSnaks(qualifiers);
|
||||||
Claim claim = Datamodel.makeClaim(subject, mainSnak, groupedQualifiers);
|
Claim claim = Datamodel.makeClaim(subject, mainSnak, groupedQualifiers);
|
||||||
|
|
||||||
// evaluate references
|
// evaluate references
|
||||||
List<Reference> references = new ArrayList<Reference>();
|
List<Reference> references = new ArrayList<Reference>();
|
||||||
for (WbReferenceExpr rExpr : getReferences()) {
|
for (WbReferenceExpr rExpr : getReferences()) {
|
||||||
try {
|
try {
|
||||||
references.add(rExpr.evaluate(ctxt));
|
references.add(rExpr.evaluate(ctxt));
|
||||||
} catch(SkipSchemaExpressionException e) {
|
} catch (SkipSchemaExpressionException e) {
|
||||||
QAWarning warning = new QAWarning(
|
QAWarning warning = new QAWarning("ignored-references", null, QAWarning.Severity.INFO, 1);
|
||||||
"ignored-references",
|
|
||||||
null,
|
|
||||||
QAWarning.Severity.INFO,
|
|
||||||
1);
|
|
||||||
warning.setProperty("example_entity", subject);
|
warning.setProperty("example_entity", subject);
|
||||||
warning.setProperty("example_property_entity", mainSnak.getPropertyId());
|
warning.setProperty("example_property_entity", mainSnak.getPropertyId());
|
||||||
ctxt.addWarning(warning);
|
ctxt.addWarning(warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementRank rank = StatementRank.NORMAL;
|
StatementRank rank = StatementRank.NORMAL;
|
||||||
return Datamodel.makeStatement(claim, references, rank, "");
|
return Datamodel.makeStatement(claim, references, rank, "");
|
||||||
}
|
}
|
||||||
@ -115,18 +129,17 @@ public class WbStatementExpr {
|
|||||||
public List<WbReferenceExpr> getReferences() {
|
public List<WbReferenceExpr> getReferences() {
|
||||||
return referenceExprs;
|
return referenceExprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null || !WbStatementExpr.class.isInstance(other)) {
|
if (other == null || !WbStatementExpr.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbStatementExpr otherExpr = (WbStatementExpr)other;
|
WbStatementExpr otherExpr = (WbStatementExpr) other;
|
||||||
return mainSnakValueExpr.equals(otherExpr.getMainsnak()) &&
|
return mainSnakValueExpr.equals(otherExpr.getMainsnak()) && qualifierExprs.equals(otherExpr.getQualifiers())
|
||||||
qualifierExprs.equals(otherExpr.getQualifiers()) &&
|
&& referenceExprs.equals(otherExpr.getReferences());
|
||||||
referenceExprs.equals(otherExpr.getReferences());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return mainSnakValueExpr.hashCode() + qualifierExprs.hashCode() + referenceExprs.hashCode();
|
return mainSnakValueExpr.hashCode() + qualifierExprs.hashCode() + referenceExprs.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -14,17 +37,15 @@ import org.wikidata.wdtk.datamodel.interfaces.StatementGroup;
|
|||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class WbStatementGroupExpr {
|
public class WbStatementGroupExpr {
|
||||||
|
|
||||||
private WbExpression<? extends PropertyIdValue> propertyExpr;
|
private WbExpression<? extends PropertyIdValue> propertyExpr;
|
||||||
private List<WbStatementExpr> statementExprs;
|
private List<WbStatementExpr> statementExprs;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbStatementGroupExpr(
|
public WbStatementGroupExpr(@JsonProperty("property") WbExpression<? extends PropertyIdValue> propertyExpr,
|
||||||
@JsonProperty("property") WbExpression<? extends PropertyIdValue> propertyExpr,
|
|
||||||
@JsonProperty("statements") List<WbStatementExpr> claimExprs) {
|
@JsonProperty("statements") List<WbStatementExpr> claimExprs) {
|
||||||
Validate.notNull(propertyExpr);
|
Validate.notNull(propertyExpr);
|
||||||
this.propertyExpr = propertyExpr;
|
this.propertyExpr = propertyExpr;
|
||||||
@ -33,10 +54,11 @@ public class WbStatementGroupExpr {
|
|||||||
this.statementExprs = claimExprs;
|
this.statementExprs = claimExprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatementGroup evaluate(ExpressionContext ctxt, ItemIdValue subject) throws SkipSchemaExpressionException {
|
public StatementGroup evaluate(ExpressionContext ctxt, ItemIdValue subject)
|
||||||
|
throws SkipSchemaExpressionException {
|
||||||
PropertyIdValue propertyId = propertyExpr.evaluate(ctxt);
|
PropertyIdValue propertyId = propertyExpr.evaluate(ctxt);
|
||||||
List<Statement> statements = new ArrayList<Statement>(statementExprs.size());
|
List<Statement> statements = new ArrayList<Statement>(statementExprs.size());
|
||||||
for(WbStatementExpr expr : statementExprs) {
|
for (WbStatementExpr expr : statementExprs) {
|
||||||
try {
|
try {
|
||||||
statements.add(expr.evaluate(ctxt, subject, propertyId));
|
statements.add(expr.evaluate(ctxt, subject, propertyId));
|
||||||
} catch (SkipSchemaExpressionException e) {
|
} catch (SkipSchemaExpressionException e) {
|
||||||
@ -59,17 +81,16 @@ public class WbStatementGroupExpr {
|
|||||||
public List<WbStatementExpr> getStatements() {
|
public List<WbStatementExpr> getStatements() {
|
||||||
return statementExprs;
|
return statementExprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null || !WbStatementGroupExpr.class.isInstance(other)) {
|
if (other == null || !WbStatementGroupExpr.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WbStatementGroupExpr otherExpr = (WbStatementGroupExpr)other;
|
WbStatementGroupExpr otherExpr = (WbStatementGroupExpr) other;
|
||||||
return propertyExpr.equals(otherExpr.getProperty()) &&
|
return propertyExpr.equals(otherExpr.getProperty()) && statementExprs.equals(otherExpr.getStatements());
|
||||||
statementExprs.equals(otherExpr.getStatements());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return propertyExpr.hashCode() + statementExprs.hashCode();
|
return propertyExpr.hashCode() + statementExprs.hashCode();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.apache.commons.lang.Validate;
|
import org.apache.commons.lang.Validate;
|
||||||
@ -7,22 +30,21 @@ import org.wikidata.wdtk.datamodel.interfaces.StringValue;
|
|||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
|
||||||
public class WbStringConstant implements WbExpression<StringValue> {
|
public class WbStringConstant implements WbExpression<StringValue> {
|
||||||
|
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbStringConstant(@JsonProperty("value") String value) {
|
public WbStringConstant(@JsonProperty("value") String value) {
|
||||||
Validate.notNull(value);
|
Validate.notNull(value);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StringValue evaluate(ExpressionContext ctxt) {
|
public StringValue evaluate(ExpressionContext ctxt) {
|
||||||
return Datamodel.makeStringValue(value);
|
return Datamodel.makeStringValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty("value")
|
@JsonProperty("value")
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
||||||
@ -15,17 +38,17 @@ import com.google.refine.model.Cell;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WbStringVariable extends WbVariableExpr<StringValue> {
|
public class WbStringVariable extends WbVariableExpr<StringValue> {
|
||||||
|
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public WbStringVariable() {
|
public WbStringVariable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a variable and sets the column it is bound to. Mostly
|
* Constructs a variable and sets the column it is bound to. Mostly used as a
|
||||||
* used as a convenience method for testing.
|
* convenience method for testing.
|
||||||
*
|
*
|
||||||
* @param columnName
|
* @param columnName
|
||||||
* the name of the column the expression should draw its value from
|
* the name of the column the expression should draw its value from
|
||||||
*/
|
*/
|
||||||
public WbStringVariable(String columnName) {
|
public WbStringVariable(String columnName) {
|
||||||
setColumnName(columnName);
|
setColumnName(columnName);
|
||||||
@ -39,7 +62,7 @@ public class WbStringVariable extends WbVariableExpr<StringValue> {
|
|||||||
}
|
}
|
||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return equalAsVariables(other, WbStringVariable.class);
|
return equalAsVariables(other, WbStringVariable.class);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
||||||
@ -8,18 +31,18 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import com.google.refine.model.Cell;
|
import com.google.refine.model.Cell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class for expressions which draw their values
|
* A base class for expressions which draw their values from a particular
|
||||||
* from a particular column.
|
* column.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* the type of Wikibase value returned by the expression.
|
* the type of Wikibase value returned by the expression.
|
||||||
*/
|
*/
|
||||||
public abstract class WbVariableExpr<T> implements WbExpression<T> {
|
public abstract class WbVariableExpr<T> implements WbExpression<T> {
|
||||||
|
|
||||||
private String columnName;
|
private String columnName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a variable without setting the column name yet.
|
* Constructs a variable without setting the column name yet.
|
||||||
*/
|
*/
|
||||||
@ -27,21 +50,20 @@ public abstract class WbVariableExpr<T> implements WbExpression<T> {
|
|||||||
public WbVariableExpr() {
|
public WbVariableExpr() {
|
||||||
columnName = null;
|
columnName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the column name used by the variable.
|
* Returns the column name used by the variable.
|
||||||
* @return
|
*
|
||||||
* the OpenRefine column name
|
* @return the OpenRefine column name
|
||||||
*/
|
*/
|
||||||
@JsonProperty("columnName")
|
@JsonProperty("columnName")
|
||||||
public String getColumnName() {
|
public String getColumnName() {
|
||||||
return columnName;
|
return columnName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the column name used by the variable.
|
* Changes the column name used by the variable. This is useful for
|
||||||
* This is useful for deserialization, as well as updates when
|
* deserialization, as well as updates when column names change.
|
||||||
* column names change.
|
|
||||||
*/
|
*/
|
||||||
@JsonProperty("columnName")
|
@JsonProperty("columnName")
|
||||||
public void setColumnName(String columnName) {
|
public void setColumnName(String columnName) {
|
||||||
@ -60,43 +82,42 @@ public abstract class WbVariableExpr<T> implements WbExpression<T> {
|
|||||||
}
|
}
|
||||||
throw new SkipSchemaExpressionException();
|
throw new SkipSchemaExpressionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method that should be implemented by subclasses,
|
* Method that should be implemented by subclasses, converting an OpenRefine
|
||||||
* converting an OpenRefine cell to a Wikibase value.
|
* cell to a Wikibase value. Access to other values and emiting warnings is
|
||||||
* Access to other values and emiting warnings is possible via
|
* possible via the supplied EvaluationContext object.
|
||||||
* the supplied EvaluationContext object.
|
|
||||||
*
|
*
|
||||||
* @param cell
|
* @param cell
|
||||||
* the cell to convert
|
* the cell to convert
|
||||||
* @param ctxt
|
* @param ctxt
|
||||||
* the evaluation context
|
* the evaluation context
|
||||||
* @return
|
* @return the corresponding Wikibase value
|
||||||
* the corresponding Wikibase value
|
|
||||||
*/
|
*/
|
||||||
public abstract T fromCell(Cell cell, ExpressionContext ctxt) throws SkipSchemaExpressionException;
|
public abstract T fromCell(Cell cell, ExpressionContext ctxt)
|
||||||
|
throws SkipSchemaExpressionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for equality methods of subclasses.
|
* Helper for equality methods of subclasses.
|
||||||
*
|
*
|
||||||
* @param other
|
* @param other
|
||||||
* the object to compare
|
* the object to compare
|
||||||
* @param columnName
|
* @param columnName
|
||||||
* the column name to compare to
|
* the column name to compare to
|
||||||
* @param targetClass
|
* @param targetClass
|
||||||
* the target class for equality
|
* the target class for equality
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected boolean equalAsVariables(Object other, Class<? extends WbVariableExpr<?>> targetClass) {
|
protected boolean equalAsVariables(Object other, Class<? extends WbVariableExpr<?>> targetClass) {
|
||||||
if(other == null || !targetClass.isInstance(other)) {
|
if (other == null || !targetClass.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return columnName.equals(targetClass.cast(other).getColumnName());
|
return columnName.equals(targetClass.cast(other).getColumnName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return columnName.hashCode();
|
return columnName.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema;
|
package org.openrefine.wikidata.schema;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -8,6 +31,10 @@ 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 org.openrefine.wikidata.qa.QAWarningStore;
|
||||||
|
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
||||||
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
|
import org.openrefine.wikidata.utils.JacksonJsonizable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -17,17 +44,10 @@ import com.google.refine.browsing.RowVisitor;
|
|||||||
import com.google.refine.model.OverlayModel;
|
import com.google.refine.model.OverlayModel;
|
||||||
import com.google.refine.model.Project;
|
import com.google.refine.model.Project;
|
||||||
import com.google.refine.model.Row;
|
import com.google.refine.model.Row;
|
||||||
import org.openrefine.wikidata.schema.WbItemDocumentExpr;
|
|
||||||
import org.openrefine.wikidata.schema.exceptions.SkipSchemaExpressionException;
|
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
|
||||||
import org.openrefine.wikidata.updates.ItemUpdateBuilder;
|
|
||||||
import org.openrefine.wikidata.qa.QAWarningStore;
|
|
||||||
import org.openrefine.wikidata.schema.ExpressionContext;
|
|
||||||
import org.openrefine.wikidata.utils.JacksonJsonizable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main class representing a skeleton of Wikibase edits with
|
* Main class representing a skeleton of Wikibase edits with OpenRefine columns
|
||||||
* OpenRefine columns as variables.
|
* as variables.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
@ -35,18 +55,18 @@ import org.openrefine.wikidata.utils.JacksonJsonizable;
|
|||||||
public class WikibaseSchema implements OverlayModel {
|
public class WikibaseSchema implements OverlayModel {
|
||||||
|
|
||||||
final static Logger logger = LoggerFactory.getLogger("RdfSchema");
|
final static Logger logger = LoggerFactory.getLogger("RdfSchema");
|
||||||
|
|
||||||
protected List<WbItemDocumentExpr> itemDocumentExprs = new ArrayList<WbItemDocumentExpr>();
|
protected List<WbItemDocumentExpr> itemDocumentExprs = new ArrayList<WbItemDocumentExpr>();
|
||||||
|
|
||||||
protected String baseIri = "http://www.wikidata.org/entity/";
|
protected String baseIri = "http://www.wikidata.org/entity/";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public WikibaseSchema() {
|
public WikibaseSchema() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the site IRI of the Wikibase instance referenced by this schema
|
* @return the site IRI of the Wikibase instance referenced by this schema
|
||||||
*/
|
*/
|
||||||
@ -60,24 +80,24 @@ public class WikibaseSchema implements OverlayModel {
|
|||||||
public List<WbItemDocumentExpr> getItemDocumentExpressions() {
|
public List<WbItemDocumentExpr> getItemDocumentExpressions() {
|
||||||
return itemDocumentExprs;
|
return itemDocumentExprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setItemDocumentExpressions(List<WbItemDocumentExpr> exprs) {
|
public void setItemDocumentExpressions(List<WbItemDocumentExpr> exprs) {
|
||||||
this.itemDocumentExprs = exprs;
|
this.itemDocumentExprs = exprs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates all item documents in a particular expression context.
|
* Evaluates all item documents in a particular expression context. This
|
||||||
* This specifies, among others, a row where the values of the variables
|
* specifies, among others, a row where the values of the variables will be
|
||||||
* will be read.
|
* read.
|
||||||
*
|
*
|
||||||
* @param ctxt
|
* @param ctxt
|
||||||
* the context in which the schema should be evaluated.
|
* the context in which the schema should be evaluated.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public List<ItemUpdate> evaluateItemDocuments(ExpressionContext ctxt) {
|
public List<ItemUpdate> evaluateItemDocuments(ExpressionContext ctxt) {
|
||||||
List<ItemUpdate> result = new ArrayList<>();
|
List<ItemUpdate> result = new ArrayList<>();
|
||||||
for (WbItemDocumentExpr expr : itemDocumentExprs) {
|
for (WbItemDocumentExpr expr : itemDocumentExprs) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result.add(expr.evaluate(ctxt));
|
result.add(expr.evaluate(ctxt));
|
||||||
} catch (SkipSchemaExpressionException e) {
|
} catch (SkipSchemaExpressionException e) {
|
||||||
@ -86,24 +106,23 @@ public class WikibaseSchema implements OverlayModel {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the schema on a project, returning a list of ItemUpdates
|
* Evaluates the schema on a project, returning a list of ItemUpdates generated
|
||||||
* generated by the schema.
|
* by the schema.
|
||||||
*
|
*
|
||||||
* Some warnings will be emitted in the warning store: those are only
|
* Some warnings will be emitted in the warning store: those are only the ones
|
||||||
* the ones that are generated at evaluation time (such as invalid formats
|
* that are generated at evaluation time (such as invalid formats for dates).
|
||||||
* for dates). Issues detected on candidate statements (such as constraint
|
* Issues detected on candidate statements (such as constraint violations) are
|
||||||
* violations) are not included at this stage.
|
* not included at this stage.
|
||||||
*
|
*
|
||||||
* @param project
|
* @param project
|
||||||
* the project on which the schema should be evaluated
|
* the project on which the schema should be evaluated
|
||||||
* @param engine
|
* @param engine
|
||||||
* the engine, which gives access to the current facets
|
* the engine, which gives access to the current facets
|
||||||
* @param warningStore
|
* @param warningStore
|
||||||
* a store in which issues will be emitted
|
* a store in which issues will be emitted
|
||||||
* @return item updates are stored in their
|
* @return item updates are stored in their generating order (not merged yet).
|
||||||
* generating order (not merged yet).
|
|
||||||
*/
|
*/
|
||||||
public List<ItemUpdate> evaluate(Project project, Engine engine, QAWarningStore warningStore) {
|
public List<ItemUpdate> evaluate(Project project, Engine engine, QAWarningStore warningStore) {
|
||||||
List<ItemUpdate> result = new ArrayList<>();
|
List<ItemUpdate> result = new ArrayList<>();
|
||||||
@ -111,35 +130,32 @@ public class WikibaseSchema implements OverlayModel {
|
|||||||
filteredRows.accept(project, new EvaluatingRowVisitor(result, warningStore));
|
filteredRows.accept(project, new EvaluatingRowVisitor(result, warningStore));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as above, ignoring any warnings.
|
* Same as above, ignoring any warnings.
|
||||||
*/
|
*/
|
||||||
public List<ItemUpdate> evaluate(Project project, Engine engine) {
|
public List<ItemUpdate> evaluate(Project project, Engine engine) {
|
||||||
return evaluate(project, engine, null);
|
return evaluate(project, engine, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class EvaluatingRowVisitor implements RowVisitor {
|
protected class EvaluatingRowVisitor implements RowVisitor {
|
||||||
|
|
||||||
private List<ItemUpdate> result;
|
private List<ItemUpdate> result;
|
||||||
private QAWarningStore warningStore;
|
private QAWarningStore warningStore;
|
||||||
|
|
||||||
public EvaluatingRowVisitor(List<ItemUpdate> result, QAWarningStore warningStore) {
|
public EvaluatingRowVisitor(List<ItemUpdate> result, QAWarningStore warningStore) {
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.warningStore = warningStore;
|
this.warningStore = warningStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Project project) {
|
public void start(Project project) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visit(Project project, int rowIndex, Row row) {
|
public boolean visit(Project project, int rowIndex, Row row) {
|
||||||
ExpressionContext ctxt = new ExpressionContext(
|
ExpressionContext ctxt = new ExpressionContext(baseIri, rowIndex, row, project.columnModel, warningStore);
|
||||||
baseIri,
|
|
||||||
rowIndex,
|
|
||||||
row,
|
|
||||||
project.columnModel,
|
|
||||||
warningStore);
|
|
||||||
result.addAll(evaluateItemDocuments(ctxt));
|
result.addAll(evaluateItemDocuments(ctxt));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -150,12 +166,14 @@ public class WikibaseSchema implements OverlayModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static public WikibaseSchema reconstruct(JSONObject o) throws JSONException {
|
static public WikibaseSchema reconstruct(JSONObject o)
|
||||||
|
throws JSONException {
|
||||||
|
|
||||||
JSONArray changeArr = o.getJSONArray("itemDocuments");
|
JSONArray changeArr = o.getJSONArray("itemDocuments");
|
||||||
WikibaseSchema schema = new WikibaseSchema();
|
WikibaseSchema schema = new WikibaseSchema();
|
||||||
for (int i = 0; i != changeArr.length(); i++) {
|
for (int i = 0; i != changeArr.length(); i++) {
|
||||||
WbItemDocumentExpr changeExpr = JacksonJsonizable.fromJSONClass(changeArr.getJSONObject(i), WbItemDocumentExpr.class);
|
WbItemDocumentExpr changeExpr = JacksonJsonizable.fromJSONClass(changeArr.getJSONObject(i),
|
||||||
|
WbItemDocumentExpr.class);
|
||||||
schema.itemDocumentExprs.add(changeExpr);
|
schema.itemDocumentExprs.add(changeExpr);
|
||||||
}
|
}
|
||||||
return schema;
|
return schema;
|
||||||
@ -173,30 +191,31 @@ public class WikibaseSchema implements OverlayModel {
|
|||||||
writer.endArray();
|
writer.endArray();
|
||||||
writer.endObject();
|
writer.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
static public WikibaseSchema load(Project project, JSONObject obj) throws Exception {
|
static public WikibaseSchema load(Project project, JSONObject obj)
|
||||||
|
throws Exception {
|
||||||
return reconstruct(obj);
|
return reconstruct(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBeforeSave(Project project) {
|
public void onBeforeSave(Project project) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAfterSave(Project project) {
|
public void onAfterSave(Project project) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose(Project project) {
|
public void dispose(Project project) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !WikibaseSchema.class.isInstance(other)) {
|
if (other == null || !WikibaseSchema.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
WikibaseSchema otherSchema = (WikibaseSchema)other;
|
WikibaseSchema otherSchema = (WikibaseSchema) other;
|
||||||
return itemDocumentExprs.equals(otherSchema.getItemDocumentExpressions());
|
return itemDocumentExprs.equals(otherSchema.getItemDocumentExpressions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.entityvalues;
|
package org.openrefine.wikidata.schema.entityvalues;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -5,34 +28,31 @@ import java.util.List;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An entity id value that also comes with
|
* An entity id value that also comes with a label and possibly types.
|
||||||
* a label and possibly types.
|
|
||||||
*
|
*
|
||||||
* The rationale behind this classes is that OpenRefine
|
* The rationale behind this classes is that OpenRefine already stores labels
|
||||||
* already stores labels and types for the Wikidata items
|
* and types for the Wikidata items it knows about (in the reconciliation data),
|
||||||
* it knows about (in the reconciliation data), so it is
|
* so it is worth keeping this data to avoid re-fetching it when we need it.
|
||||||
* worth keeping this data to avoid re-fetching it when
|
|
||||||
* we need it.
|
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface PrefetchedEntityIdValue extends EntityIdValue {
|
public interface PrefetchedEntityIdValue extends EntityIdValue {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should return the label "as we got it", with no guarantee
|
* This should return the label "as we got it", with no guarantee that it is
|
||||||
* that it is current or that its language matches that of the user.
|
* current or that its language matches that of the user. In general though,
|
||||||
* In general though, that should be the case if the user always uses
|
* that should be the case if the user always uses OpenRefine with the same
|
||||||
* OpenRefine with the same language settings.
|
* language settings.
|
||||||
*
|
*
|
||||||
* @return the preferred label of the entity
|
* @return the preferred label of the entity
|
||||||
*/
|
*/
|
||||||
public String getLabel();
|
public String getLabel();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of types for this item. Again these are the types
|
* Returns a list of types for this item. Again these are the types as they were
|
||||||
* as they were originally fetched from the reconciliation interface:
|
* originally fetched from the reconciliation interface: they can diverge from
|
||||||
* they can diverge from what is currently on the item.
|
* what is currently on the item.
|
||||||
*
|
*
|
||||||
* Empty lists should be returned for
|
* Empty lists should be returned for
|
||||||
*/
|
*/
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.entityvalues;
|
package org.openrefine.wikidata.schema.entityvalues;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -14,43 +37,41 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||||||
import com.google.refine.model.Recon;
|
import com.google.refine.model.Recon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An EntityIdValue that holds not just the id but also
|
* An EntityIdValue that holds not just the id but also the label as fetched by
|
||||||
* the label as fetched by either the reconciliation interface
|
* either the reconciliation interface or the suggester and its type, both
|
||||||
* or the suggester and its type, both stored as reconciliation
|
* stored as reconciliation candidates.
|
||||||
* candidates.
|
|
||||||
*
|
*
|
||||||
* This label will be localized depending on the language chosen
|
* This label will be localized depending on the language chosen by the user for
|
||||||
* by the user for OpenRefine's interface. Storing it lets us
|
* OpenRefine's interface. Storing it lets us reuse it later on without having
|
||||||
* reuse it later on without having to re-fetch it.
|
* to re-fetch it.
|
||||||
*
|
*
|
||||||
* Storing the types also lets us perform some constraint checks
|
* Storing the types also lets us perform some constraint checks without
|
||||||
* without re-fetching the types of many items.
|
* re-fetching the types of many items.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class ReconEntityIdValue implements PrefetchedEntityIdValue {
|
public abstract class ReconEntityIdValue implements PrefetchedEntityIdValue {
|
||||||
|
|
||||||
private Recon _recon;
|
private Recon _recon;
|
||||||
private String _cellValue;
|
private String _cellValue;
|
||||||
|
|
||||||
public ReconEntityIdValue(Recon match, String cellValue) {
|
public ReconEntityIdValue(Recon match, String cellValue) {
|
||||||
_recon = match;
|
_recon = match;
|
||||||
_cellValue = cellValue;
|
_cellValue = cellValue;
|
||||||
assert (Recon.Judgment.Matched.equals(_recon.judgment) ||
|
assert (Recon.Judgment.Matched.equals(_recon.judgment) || Recon.Judgment.New.equals(_recon.judgment));
|
||||||
Recon.Judgment.New.equals(_recon.judgment));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isMatched() {
|
public boolean isMatched() {
|
||||||
return Recon.Judgment.Matched.equals(_recon.judgment) && _recon.match != null;
|
return Recon.Judgment.Matched.equals(_recon.judgment) && _recon.match != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isNew() {
|
public boolean isNew() {
|
||||||
return !isMatched();
|
return !isMatched();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
if (isMatched()) {
|
if (isMatched()) {
|
||||||
return _recon.match.name;
|
return _recon.match.name;
|
||||||
@ -66,32 +87,28 @@ public abstract class ReconEntityIdValue implements PrefetchedEntityIdValue {
|
|||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract String getEntityType();
|
public abstract String getEntityType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the integer used internally in OpenRefine to identify the new
|
* Returns the integer used internally in OpenRefine to identify the new item.
|
||||||
* item.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return the judgment history entry id of the reconciled cell
|
||||||
* the judgment history entry id of the reconciled cell
|
|
||||||
*/
|
*/
|
||||||
public long getReconInternalId() {
|
public long getReconInternalId() {
|
||||||
return getRecon().judgmentHistoryEntry;
|
return getRecon().judgmentHistoryEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the reconciliation object corresponding to this entity.
|
* Returns the reconciliation object corresponding to this entity.
|
||||||
*
|
*
|
||||||
* @return
|
* @return the full reconciliation metadata of the corresponding cell
|
||||||
* the full reconciliation metadata of the corresponding cell
|
|
||||||
*/
|
*/
|
||||||
public Recon getRecon() {
|
public Recon getRecon() {
|
||||||
return _recon;
|
return _recon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the id of the reconciled item
|
* Returns the id of the reconciled item
|
||||||
*/
|
*/
|
||||||
@ -100,9 +117,9 @@ public abstract class ReconEntityIdValue implements PrefetchedEntityIdValue {
|
|||||||
if (isMatched()) {
|
if (isMatched()) {
|
||||||
return _recon.match.id;
|
return _recon.match.id;
|
||||||
} else if (ET_ITEM.equals(getEntityType())) {
|
} else if (ET_ITEM.equals(getEntityType())) {
|
||||||
return "Q"+getReconInternalId();
|
return "Q" + getReconInternalId();
|
||||||
} else if (ET_PROPERTY.equals(getEntityType())) {
|
} else if (ET_PROPERTY.equals(getEntityType())) {
|
||||||
return "P"+getReconInternalId();
|
return "P" + getReconInternalId();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -125,13 +142,13 @@ public abstract class ReconEntityIdValue implements PrefetchedEntityIdValue {
|
|||||||
public <T> T accept(ValueVisitor<T> valueVisitor) {
|
public <T> T accept(ValueVisitor<T> valueVisitor) {
|
||||||
return valueVisitor.visit(this);
|
return valueVisitor.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return Equality.equalsEntityIdValue(this, other);
|
return Equality.equalsEntityIdValue(this, other);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Hash.hashCode(this);
|
return Hash.hashCode(this);
|
||||||
@ -139,10 +156,10 @@ public abstract class ReconEntityIdValue implements PrefetchedEntityIdValue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if(isNew()) {
|
if (isNew()) {
|
||||||
return "new item (reconciled from " + getReconInternalId() +")";
|
return "new item (reconciled from " + getReconInternalId() + ")";
|
||||||
} else {
|
} else {
|
||||||
return getIri() + " (reconciled from " + getReconInternalId()+")";
|
return getIri() + " (reconciled from " + getReconInternalId() + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.entityvalues;
|
package org.openrefine.wikidata.schema.entityvalues;
|
||||||
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.entityvalues;
|
package org.openrefine.wikidata.schema.entityvalues;
|
||||||
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
||||||
|
@ -1,22 +1,44 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.entityvalues;
|
package org.openrefine.wikidata.schema.entityvalues;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.wikidata.wdtk.datamodel.helpers.Hash;
|
import org.wikidata.wdtk.datamodel.helpers.Hash;
|
||||||
import org.wikidata.wdtk.datamodel.helpers.ToString;
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ValueVisitor;
|
import org.wikidata.wdtk.datamodel.interfaces.ValueVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An EntityIdValue that we have obtained from a suggest widget
|
* An EntityIdValue that we have obtained from a suggest widget in the schema
|
||||||
* in the schema alignment dialog.
|
* alignment dialog.
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class SuggestedEntityIdValue implements PrefetchedEntityIdValue {
|
public abstract class SuggestedEntityIdValue implements PrefetchedEntityIdValue {
|
||||||
|
|
||||||
private String _id;
|
private String _id;
|
||||||
private String _siteIRI;
|
private String _siteIRI;
|
||||||
private String _label;
|
private String _label;
|
||||||
@ -31,22 +53,22 @@ public abstract class SuggestedEntityIdValue implements PrefetchedEntityIdValue
|
|||||||
public String getId() {
|
public String getId() {
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSiteIri() {
|
public String getSiteIri() {
|
||||||
return _siteIRI;
|
return _siteIRI;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel() {
|
public String getLabel() {
|
||||||
return _label;
|
return _label;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getTypes() {
|
public List<String> getTypes() {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIri() {
|
public String getIri() {
|
||||||
return getSiteIri() + getId();
|
return getSiteIri() + getId();
|
||||||
@ -56,14 +78,13 @@ public abstract class SuggestedEntityIdValue implements PrefetchedEntityIdValue
|
|||||||
public <T> T accept(ValueVisitor<T> valueVisitor) {
|
public <T> T accept(ValueVisitor<T> valueVisitor) {
|
||||||
return valueVisitor.visit(this);
|
return valueVisitor.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null ||
|
if (other == null || !EntityIdValue.class.isInstance(other)) {
|
||||||
!EntityIdValue.class.isInstance(other)) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
final EntityIdValue otherNew = (EntityIdValue)other;
|
final EntityIdValue otherNew = (EntityIdValue) other;
|
||||||
return getIri().equals(otherNew.getIri());
|
return getIri().equals(otherNew.getIri());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.entityvalues;
|
package org.openrefine.wikidata.schema.entityvalues;
|
||||||
|
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.entityvalues;
|
package org.openrefine.wikidata.schema.entityvalues;
|
||||||
|
|
||||||
import org.wikidata.wdtk.datamodel.helpers.ToString;
|
import org.wikidata.wdtk.datamodel.helpers.ToString;
|
||||||
@ -16,6 +39,6 @@ public class SuggestedPropertyIdValue extends SuggestedEntityIdValue implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "suggested "+ToString.toString(this)+" (\""+getLabel()+"\")";
|
return "suggested " + ToString.toString(this) + " (\"" + getLabel() + "\")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,29 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.exceptions;
|
package org.openrefine.wikidata.schema.exceptions;
|
||||||
|
|
||||||
|
|
||||||
public class InvalidSchemaException extends Exception {
|
public class InvalidSchemaException extends Exception {
|
||||||
|
|
||||||
static final long serialVersionUID = 494837587034L;
|
static final long serialVersionUID = 494837587034L;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,29 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.schema.exceptions;
|
package org.openrefine.wikidata.schema.exceptions;
|
||||||
|
|
||||||
|
|
||||||
public class SkipSchemaExpressionException extends Exception {
|
public class SkipSchemaExpressionException extends Exception {
|
||||||
|
|
||||||
static final long serialVersionUID = 738592057L;
|
static final long serialVersionUID = 738592057L;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates;
|
package org.openrefine.wikidata.updates;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -23,42 +46,43 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to plan an update of an item, after evaluating the statements
|
* A class to plan an update of an item, after evaluating the statements but
|
||||||
* but before fetching the current content of the item (this is why it does not
|
* before fetching the current content of the item (this is why it does not
|
||||||
* extend StatementsUpdate).
|
* extend StatementsUpdate).
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*/
|
*/
|
||||||
public class ItemUpdate {
|
public class ItemUpdate {
|
||||||
|
|
||||||
private final ItemIdValue qid;
|
private final ItemIdValue qid;
|
||||||
private final List<Statement> addedStatements;
|
private final List<Statement> addedStatements;
|
||||||
private final Set<Statement> deletedStatements;
|
private final Set<Statement> deletedStatements;
|
||||||
private final Set<MonolingualTextValue> labels;
|
private final Set<MonolingualTextValue> labels;
|
||||||
private final Set<MonolingualTextValue> descriptions;
|
private final Set<MonolingualTextValue> descriptions;
|
||||||
private final Set<MonolingualTextValue> aliases;
|
private final Set<MonolingualTextValue> aliases;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param qid
|
* @param qid
|
||||||
* the subject of the document. It can be a reconciled item value for new items.
|
* the subject of the document. It can be a reconciled item value for
|
||||||
|
* new items.
|
||||||
* @param addedStatements
|
* @param addedStatements
|
||||||
* the statements to add on the item. They should be distinct. They
|
* the statements to add on the item. They should be distinct. They
|
||||||
* are modelled as a list because their insertion order matters.
|
* are modelled as a list because their insertion order matters.
|
||||||
* @param deletedStatements
|
* @param deletedStatements
|
||||||
* the statements to remove from the item
|
* the statements to remove from the item
|
||||||
* @param labels
|
* @param labels
|
||||||
* the labels to add on the item
|
* the labels to add on the item
|
||||||
* @param descriptions
|
* @param descriptions
|
||||||
* the descriptions to add on the item
|
* the descriptions to add on the item
|
||||||
* @param aliases
|
* @param aliases
|
||||||
* the aliases to add on the item. In theory their order should matter
|
* the aliases to add on the item. In theory their order should
|
||||||
* but in practice people rarely rely on the order of aliases so this
|
* matter but in practice people rarely rely on the order of aliases
|
||||||
* is just kept as a set for simplicity.
|
* so this is just kept as a set for simplicity.
|
||||||
*/
|
*/
|
||||||
@JsonCreator
|
@JsonCreator
|
||||||
public ItemUpdate(
|
public ItemUpdate(@JsonProperty("subject") ItemIdValue qid,
|
||||||
@JsonProperty("subject") ItemIdValue qid,
|
|
||||||
@JsonProperty("addedStatements") List<Statement> addedStatements,
|
@JsonProperty("addedStatements") List<Statement> addedStatements,
|
||||||
@JsonProperty("deletedStatements") Set<Statement> deletedStatements,
|
@JsonProperty("deletedStatements") Set<Statement> deletedStatements,
|
||||||
@JsonProperty("labels") Set<MonolingualTextValue> labels,
|
@JsonProperty("labels") Set<MonolingualTextValue> labels,
|
||||||
@ -66,28 +90,28 @@ public class ItemUpdate {
|
|||||||
@JsonProperty("addedAliases") Set<MonolingualTextValue> aliases) {
|
@JsonProperty("addedAliases") Set<MonolingualTextValue> aliases) {
|
||||||
Validate.notNull(qid);
|
Validate.notNull(qid);
|
||||||
this.qid = qid;
|
this.qid = qid;
|
||||||
if(addedStatements == null) {
|
if (addedStatements == null) {
|
||||||
addedStatements = Collections.emptyList();
|
addedStatements = Collections.emptyList();
|
||||||
}
|
}
|
||||||
this.addedStatements = addedStatements;
|
this.addedStatements = addedStatements;
|
||||||
if(deletedStatements == null) {
|
if (deletedStatements == null) {
|
||||||
deletedStatements = Collections.emptySet();
|
deletedStatements = Collections.emptySet();
|
||||||
}
|
}
|
||||||
this.deletedStatements = deletedStatements;
|
this.deletedStatements = deletedStatements;
|
||||||
if(labels == null) {
|
if (labels == null) {
|
||||||
labels = Collections.emptySet();
|
labels = Collections.emptySet();
|
||||||
}
|
}
|
||||||
this.labels = labels;
|
this.labels = labels;
|
||||||
if(descriptions == null) {
|
if (descriptions == null) {
|
||||||
descriptions = Collections.emptySet();
|
descriptions = Collections.emptySet();
|
||||||
}
|
}
|
||||||
this.descriptions = descriptions;
|
this.descriptions = descriptions;
|
||||||
if(aliases == null) {
|
if (aliases == null) {
|
||||||
aliases = Collections.emptySet();
|
aliases = Collections.emptySet();
|
||||||
}
|
}
|
||||||
this.aliases = aliases;
|
this.aliases = aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the subject of the item
|
* @return the subject of the item
|
||||||
*/
|
*/
|
||||||
@ -95,10 +119,10 @@ public class ItemUpdate {
|
|||||||
public ItemIdValue getItemId() {
|
public ItemIdValue getItemId() {
|
||||||
return qid;
|
return qid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Added statements are recorded as a list because
|
* Added statements are recorded as a list because their order of insertion
|
||||||
* their order of insertion matters.
|
* matters.
|
||||||
*
|
*
|
||||||
* @return the list of all added statements
|
* @return the list of all added statements
|
||||||
*/
|
*/
|
||||||
@ -106,7 +130,7 @@ public class ItemUpdate {
|
|||||||
public List<Statement> getAddedStatements() {
|
public List<Statement> getAddedStatements() {
|
||||||
return addedStatements;
|
return addedStatements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the list of all deleted statements
|
* @return the list of all deleted statements
|
||||||
*/
|
*/
|
||||||
@ -114,7 +138,7 @@ public class ItemUpdate {
|
|||||||
public Set<Statement> getDeletedStatements() {
|
public Set<Statement> getDeletedStatements() {
|
||||||
return deletedStatements;
|
return deletedStatements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the list of updated labels
|
* @return the list of updated labels
|
||||||
*/
|
*/
|
||||||
@ -122,7 +146,7 @@ public class ItemUpdate {
|
|||||||
public Set<MonolingualTextValue> getLabels() {
|
public Set<MonolingualTextValue> getLabels() {
|
||||||
return labels;
|
return labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the list of updated descriptions
|
* @return the list of updated descriptions
|
||||||
*/
|
*/
|
||||||
@ -130,7 +154,7 @@ public class ItemUpdate {
|
|||||||
public Set<MonolingualTextValue> getDescriptions() {
|
public Set<MonolingualTextValue> getDescriptions() {
|
||||||
return descriptions;
|
return descriptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the list of updated aliases
|
* @return the list of updated aliases
|
||||||
*/
|
*/
|
||||||
@ -138,7 +162,7 @@ public class ItemUpdate {
|
|||||||
public Set<MonolingualTextValue> getAliases() {
|
public Set<MonolingualTextValue> getAliases() {
|
||||||
return aliases;
|
return aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true when this change is empty and its subject is not new
|
* @return true when this change is empty and its subject is not new
|
||||||
*/
|
*/
|
||||||
@ -146,30 +170,27 @@ public class ItemUpdate {
|
|||||||
public boolean isNull() {
|
public boolean isNull() {
|
||||||
return isEmpty() && !isNew();
|
return isEmpty() && !isNew();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true when this change leaves the content of the document untouched
|
* @return true when this change leaves the content of the document untouched
|
||||||
*/
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return (addedStatements.isEmpty()
|
return (addedStatements.isEmpty() && deletedStatements.isEmpty() && labels.isEmpty() && descriptions.isEmpty()
|
||||||
&& deletedStatements.isEmpty()
|
|
||||||
&& labels.isEmpty()
|
|
||||||
&& descriptions.isEmpty()
|
|
||||||
&& aliases.isEmpty());
|
&& aliases.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges all the changes in other into this instance.
|
* Merges all the changes in other into this instance. Both updates should have
|
||||||
* Both updates should have the same subject.
|
* the same subject.
|
||||||
*
|
*
|
||||||
* @param other
|
* @param other
|
||||||
* the other change that should be merged
|
* the other change that should be merged
|
||||||
*/
|
*/
|
||||||
public ItemUpdate merge(ItemUpdate other) {
|
public ItemUpdate merge(ItemUpdate other) {
|
||||||
Validate.isTrue(qid.equals(other.getItemId()));
|
Validate.isTrue(qid.equals(other.getItemId()));
|
||||||
List<Statement> newAddedStatements = new ArrayList<>(addedStatements);
|
List<Statement> newAddedStatements = new ArrayList<>(addedStatements);
|
||||||
for(Statement statement : other.getAddedStatements()) {
|
for (Statement statement : other.getAddedStatements()) {
|
||||||
if (!newAddedStatements.contains(statement)) {
|
if (!newAddedStatements.contains(statement)) {
|
||||||
newAddedStatements.add(statement);
|
newAddedStatements.add(statement);
|
||||||
}
|
}
|
||||||
@ -182,20 +203,17 @@ public class ItemUpdate {
|
|||||||
newDescriptions.addAll(other.getDescriptions());
|
newDescriptions.addAll(other.getDescriptions());
|
||||||
Set<MonolingualTextValue> newAliases = new HashSet<>(aliases);
|
Set<MonolingualTextValue> newAliases = new HashSet<>(aliases);
|
||||||
newAliases.addAll(other.getAliases());
|
newAliases.addAll(other.getAliases());
|
||||||
return new ItemUpdate(
|
return new ItemUpdate(qid, newAddedStatements, newDeletedStatements, newLabels, newDescriptions, newAliases);
|
||||||
qid, newAddedStatements, newDeletedStatements,
|
|
||||||
newLabels, newDescriptions, newAliases);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group added statements in StatementGroups: useful if the
|
* Group added statements in StatementGroups: useful if the item is new.
|
||||||
* item is new.
|
|
||||||
*
|
*
|
||||||
* @return a grouped version of getAddedStatements()
|
* @return a grouped version of getAddedStatements()
|
||||||
*/
|
*/
|
||||||
public List<StatementGroup> getAddedStatementGroups() {
|
public List<StatementGroup> getAddedStatementGroups() {
|
||||||
Map<PropertyIdValue, List<Statement>> map = new HashMap<>();
|
Map<PropertyIdValue, List<Statement>> map = new HashMap<>();
|
||||||
for(Statement statement : getAddedStatements()) {
|
for (Statement statement : getAddedStatements()) {
|
||||||
PropertyIdValue propertyId = statement.getClaim().getMainSnak().getPropertyId();
|
PropertyIdValue propertyId = statement.getClaim().getMainSnak().getPropertyId();
|
||||||
if (!map.containsKey(propertyId)) {
|
if (!map.containsKey(propertyId)) {
|
||||||
map.put(propertyId, new ArrayList<Statement>());
|
map.put(propertyId, new ArrayList<Statement>());
|
||||||
@ -203,26 +221,26 @@ public class ItemUpdate {
|
|||||||
map.get(propertyId).add(statement);
|
map.get(propertyId).add(statement);
|
||||||
}
|
}
|
||||||
List<StatementGroup> result = new ArrayList<>();
|
List<StatementGroup> result = new ArrayList<>();
|
||||||
for(Map.Entry<PropertyIdValue, List<Statement>> entry : map.entrySet()) {
|
for (Map.Entry<PropertyIdValue, List<Statement>> entry : map.entrySet()) {
|
||||||
result.add(new StatementGroupImpl(entry.getValue()));
|
result.add(new StatementGroupImpl(entry.getValue()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group a list of ItemUpdates by subject: this is useful to make one single edit
|
* Group a list of ItemUpdates by subject: this is useful to make one single
|
||||||
* per item.
|
* edit per item.
|
||||||
*
|
*
|
||||||
* @param itemDocuments
|
* @param itemDocuments
|
||||||
* @return a map from item ids to merged ItemUpdate for that id
|
* @return a map from item ids to merged ItemUpdate for that id
|
||||||
*/
|
*/
|
||||||
public static Map<EntityIdValue, ItemUpdate> groupBySubject(List<ItemUpdate> itemDocuments) {
|
public static Map<EntityIdValue, ItemUpdate> groupBySubject(List<ItemUpdate> itemDocuments) {
|
||||||
Map<EntityIdValue, ItemUpdate> map = new HashMap<>();
|
Map<EntityIdValue, ItemUpdate> map = new HashMap<>();
|
||||||
for(ItemUpdate update : itemDocuments) {
|
for (ItemUpdate update : itemDocuments) {
|
||||||
if (update.isNull()) {
|
if (update.isNull()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemIdValue qid = update.getItemId();
|
ItemIdValue qid = update.getItemId();
|
||||||
if (map.containsKey(qid)) {
|
if (map.containsKey(qid)) {
|
||||||
ItemUpdate oldUpdate = map.get(qid);
|
ItemUpdate oldUpdate = map.get(qid);
|
||||||
@ -233,59 +251,53 @@ public class ItemUpdate {
|
|||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this update about a new item?
|
* Is this update about a new item?
|
||||||
*/
|
*/
|
||||||
public boolean isNew() {
|
public boolean isNew() {
|
||||||
return EntityIdValue.SITE_LOCAL.equals(getItemId().getSiteIri());
|
return EntityIdValue.SITE_LOCAL.equals(getItemId().getSiteIri());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should only be used when creating a new item.
|
* This should only be used when creating a new item. This ensures that we never
|
||||||
* This ensures that we never add an alias without adding
|
* add an alias without adding a label in the same language.
|
||||||
* a label in the same language.
|
|
||||||
*/
|
*/
|
||||||
public ItemUpdate normalizeLabelsAndAliases() {
|
public ItemUpdate normalizeLabelsAndAliases() {
|
||||||
// Ensure that we are only adding aliases with labels
|
// Ensure that we are only adding aliases with labels
|
||||||
Set<String> labelLanguages = labels.stream()
|
Set<String> labelLanguages = labels.stream().map(l -> l.getLanguageCode()).collect(Collectors.toSet());
|
||||||
.map(l -> l.getLanguageCode())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
Set<MonolingualTextValue> filteredAliases = new HashSet<>();
|
Set<MonolingualTextValue> filteredAliases = new HashSet<>();
|
||||||
Set<MonolingualTextValue> newLabels = new HashSet<>(labels);
|
Set<MonolingualTextValue> newLabels = new HashSet<>(labels);
|
||||||
for(MonolingualTextValue alias : aliases) {
|
for (MonolingualTextValue alias : aliases) {
|
||||||
if(!labelLanguages.contains(alias.getLanguageCode())) {
|
if (!labelLanguages.contains(alias.getLanguageCode())) {
|
||||||
labelLanguages.add(alias.getLanguageCode());
|
labelLanguages.add(alias.getLanguageCode());
|
||||||
newLabels.add(alias);
|
newLabels.add(alias);
|
||||||
} else {
|
} else {
|
||||||
filteredAliases.add(alias);
|
filteredAliases.add(alias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ItemUpdate(qid, addedStatements, deletedStatements,
|
return new ItemUpdate(qid, addedStatements, deletedStatements, newLabels, descriptions, filteredAliases);
|
||||||
newLabels, descriptions, filteredAliases);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if(other == null || !ItemUpdate.class.isInstance(other)) {
|
if (other == null || !ItemUpdate.class.isInstance(other)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ItemUpdate otherUpdate = (ItemUpdate)other;
|
ItemUpdate otherUpdate = (ItemUpdate) other;
|
||||||
return qid.equals(otherUpdate.getItemId())&&
|
return qid.equals(otherUpdate.getItemId()) && addedStatements.equals(otherUpdate.getAddedStatements())
|
||||||
addedStatements.equals(otherUpdate.getAddedStatements()) &&
|
&& deletedStatements.equals(otherUpdate.getDeletedStatements())
|
||||||
deletedStatements.equals(otherUpdate.getDeletedStatements()) &&
|
&& labels.equals(otherUpdate.getLabels()) && descriptions.equals(otherUpdate.getDescriptions())
|
||||||
labels.equals(otherUpdate.getLabels()) &&
|
&& aliases.equals(otherUpdate.getAliases());
|
||||||
descriptions.equals(otherUpdate.getDescriptions()) &&
|
|
||||||
aliases.equals(otherUpdate.getAliases());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return qid.hashCode() + addedStatements.hashCode() + deletedStatements.hashCode() +
|
return qid.hashCode() + addedStatements.hashCode() + deletedStatements.hashCode() + labels.hashCode()
|
||||||
labels.hashCode() + descriptions.hashCode() + aliases.hashCode();
|
+ descriptions.hashCode() + aliases.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
@ -317,5 +329,5 @@ public class ItemUpdate {
|
|||||||
builder.append("\n>");
|
builder.append("\n>");
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates;
|
package org.openrefine.wikidata.updates;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -10,7 +33,6 @@ import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue;
|
import org.wikidata.wdtk.datamodel.interfaces.MonolingualTextValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@link ItemUpdate} incrementally.
|
* Constructs a {@link ItemUpdate} incrementally.
|
||||||
*
|
*
|
||||||
@ -18,6 +40,7 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ItemUpdateBuilder {
|
public class ItemUpdateBuilder {
|
||||||
|
|
||||||
private ItemIdValue qid;
|
private ItemIdValue qid;
|
||||||
private List<Statement> addedStatements;
|
private List<Statement> addedStatements;
|
||||||
private Set<Statement> deletedStatements;
|
private Set<Statement> deletedStatements;
|
||||||
@ -25,12 +48,13 @@ public class ItemUpdateBuilder {
|
|||||||
private Set<MonolingualTextValue> descriptions;
|
private Set<MonolingualTextValue> descriptions;
|
||||||
private Set<MonolingualTextValue> aliases;
|
private Set<MonolingualTextValue> aliases;
|
||||||
private boolean built;
|
private boolean built;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param qid
|
* @param qid
|
||||||
* the subject of the document. It can be a reconciled item value for new items.
|
* the subject of the document. It can be a reconciled item value for
|
||||||
|
* new items.
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder(ItemIdValue qid) {
|
public ItemUpdateBuilder(ItemIdValue qid) {
|
||||||
Validate.notNull(qid);
|
Validate.notNull(qid);
|
||||||
@ -42,50 +66,50 @@ public class ItemUpdateBuilder {
|
|||||||
this.aliases = new HashSet<MonolingualTextValue>();
|
this.aliases = new HashSet<MonolingualTextValue>();
|
||||||
this.built = false;
|
this.built = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark a statement for insertion. If it matches an existing
|
* Mark a statement for insertion. If it matches an existing statement, it will
|
||||||
* statement, it will update the statement instead.
|
* update the statement instead.
|
||||||
*
|
*
|
||||||
* @param statement
|
* @param statement
|
||||||
* the statement to add or update
|
* the statement to add or update
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addStatement(Statement statement) {
|
public ItemUpdateBuilder addStatement(Statement statement) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
addedStatements.add(statement);
|
addedStatements.add(statement);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark a statement for deletion. If no such statement exists,
|
* Mark a statement for deletion. If no such statement exists, nothing will be
|
||||||
* nothing will be deleted.
|
* deleted.
|
||||||
*
|
*
|
||||||
* @param statement
|
* @param statement
|
||||||
* the statement to delete
|
* the statement to delete
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder deleteStatement(Statement statement) {
|
public ItemUpdateBuilder deleteStatement(Statement statement) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
deletedStatements.add(statement);
|
deletedStatements.add(statement);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a list of statement, as in {@link addStatement}.
|
* Add a list of statement, as in {@link addStatement}.
|
||||||
*
|
*
|
||||||
* @param statements
|
* @param statements
|
||||||
* the statements to add
|
* the statements to add
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addStatements(Set<Statement> statements) {
|
public ItemUpdateBuilder addStatements(Set<Statement> statements) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
addedStatements.addAll(statements);
|
addedStatements.addAll(statements);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a list of statements, as in {@link deleteStatement}.
|
* Delete a list of statements, as in {@link deleteStatement}.
|
||||||
*
|
*
|
||||||
* @param statements
|
* @param statements
|
||||||
* the statements to delete
|
* the statements to delete
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder deleteStatements(Set<Statement> statements) {
|
public ItemUpdateBuilder deleteStatements(Set<Statement> statements) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
@ -94,24 +118,24 @@ public class ItemUpdateBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a label to the item. It will override any
|
* Adds a label to the item. It will override any existing label in this
|
||||||
* existing label in this language.
|
* language.
|
||||||
*
|
*
|
||||||
* @param label
|
* @param label
|
||||||
* the label to add
|
* the label to add
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addLabel(MonolingualTextValue label) {
|
public ItemUpdateBuilder addLabel(MonolingualTextValue label) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
labels.add(label);
|
labels.add(label);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a list of labels to the item. It will override any
|
* Adds a list of labels to the item. It will override any existing label in
|
||||||
* existing label in each language.
|
* each language.
|
||||||
*
|
*
|
||||||
* @param labels
|
* @param labels
|
||||||
* the labels to add
|
* the labels to add
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addLabels(Set<MonolingualTextValue> labels) {
|
public ItemUpdateBuilder addLabels(Set<MonolingualTextValue> labels) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
@ -120,24 +144,24 @@ public class ItemUpdateBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a description to the item. It will override any existing
|
* Adds a description to the item. It will override any existing description in
|
||||||
* description in this language.
|
* this language.
|
||||||
*
|
*
|
||||||
* @param description
|
* @param description
|
||||||
* the description to add
|
* the description to add
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addDescription(MonolingualTextValue description) {
|
public ItemUpdateBuilder addDescription(MonolingualTextValue description) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
descriptions.add(description);
|
descriptions.add(description);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a list of descriptions to the item. It will override any
|
* Adds a list of descriptions to the item. It will override any existing
|
||||||
* existing description in each language.
|
* description in each language.
|
||||||
*
|
*
|
||||||
* @param descriptions
|
* @param descriptions
|
||||||
* the descriptions to add
|
* the descriptions to add
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addDescriptions(Set<MonolingualTextValue> descriptions) {
|
public ItemUpdateBuilder addDescriptions(Set<MonolingualTextValue> descriptions) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
@ -146,39 +170,39 @@ public class ItemUpdateBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an alias to the item. It will be added to any existing
|
* Adds an alias to the item. It will be added to any existing aliases in that
|
||||||
* aliases in that language.
|
* language.
|
||||||
*
|
*
|
||||||
* @param alias
|
* @param alias
|
||||||
* the alias to add
|
* the alias to add
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addAlias(MonolingualTextValue alias) {
|
public ItemUpdateBuilder addAlias(MonolingualTextValue alias) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
aliases.add(alias);
|
aliases.add(alias);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a list of aliases to the item. They will be added to any
|
* Adds a list of aliases to the item. They will be added to any existing
|
||||||
* existing aliases in each language.
|
* aliases in each language.
|
||||||
*
|
*
|
||||||
* @param aliases
|
* @param aliases
|
||||||
* the aliases to add
|
* the aliases to add
|
||||||
*/
|
*/
|
||||||
public ItemUpdateBuilder addAliases(Set<MonolingualTextValue> aliases) {
|
public ItemUpdateBuilder addAliases(Set<MonolingualTextValue> aliases) {
|
||||||
Validate.isTrue(!built, "ItemUpdate has already been built");
|
Validate.isTrue(!built, "ItemUpdate has already been built");
|
||||||
this.aliases.addAll(aliases);
|
this.aliases.addAll(aliases);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the {@link ItemUpdate}.
|
* Constructs the {@link ItemUpdate}.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ItemUpdate build() {
|
public ItemUpdate build() {
|
||||||
built = true;
|
built = true;
|
||||||
return new ItemUpdate(qid, addedStatements, deletedStatements,
|
return new ItemUpdate(qid, addedStatements, deletedStatements, labels, descriptions, aliases);
|
||||||
labels, descriptions, aliases);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,28 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates.scheduler;
|
package org.openrefine.wikidata.updates.scheduler;
|
||||||
|
|
||||||
|
|
||||||
public class ImpossibleSchedulingException extends Exception {
|
public class ImpossibleSchedulingException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 6621563898380564148L;
|
private static final long serialVersionUID = 6621563898380564148L;
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates.scheduler;
|
package org.openrefine.wikidata.updates.scheduler;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -5,7 +28,6 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconEntityIdValue;
|
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.DatatypeIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.DatatypeIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
|
||||||
@ -21,33 +43,29 @@ import org.wikidata.wdtk.datamodel.interfaces.Value;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.ValueVisitor;
|
import org.wikidata.wdtk.datamodel.interfaces.ValueVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that extracts the new entity ids referred to
|
* A class that extracts the new entity ids referred to in a statement.
|
||||||
* in a statement.
|
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PointerExtractor implements ValueVisitor<Set<ReconItemIdValue>> {
|
public class PointerExtractor implements ValueVisitor<Set<ReconItemIdValue>> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts all the new entities mentioned by this statement. This
|
* Extracts all the new entities mentioned by this statement. This does not
|
||||||
* does not include the subject of the statement.
|
* include the subject of the statement.
|
||||||
*
|
*
|
||||||
* @param statement
|
* @param statement
|
||||||
* the statement to inspect
|
* the statement to inspect
|
||||||
* @return
|
* @return the set of all new entities mentioned by the statement
|
||||||
* the set of all new entities mentioned by the statement
|
|
||||||
*/
|
*/
|
||||||
public Set<ReconItemIdValue> extractPointers(Statement statement) {
|
public Set<ReconItemIdValue> extractPointers(Statement statement) {
|
||||||
Set<ReconItemIdValue> result = new HashSet<>();
|
Set<ReconItemIdValue> result = new HashSet<>();
|
||||||
result.addAll(extractPointers(statement.getClaim().getMainSnak()));
|
result.addAll(extractPointers(statement.getClaim().getMainSnak()));
|
||||||
result.addAll(extractPointers(statement.getClaim().getQualifiers()));
|
result.addAll(extractPointers(statement.getClaim().getQualifiers()));
|
||||||
statement.getReferences().stream()
|
statement.getReferences().stream().map(l -> extractPointers(l.getSnakGroups())).forEach(s -> result.addAll(s));
|
||||||
.map(l -> extractPointers(l.getSnakGroups()))
|
|
||||||
.forEach(s -> result.addAll(s));
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts all the new entities mentioned by this list of snak groups.
|
* Extracts all the new entities mentioned by this list of snak groups.
|
||||||
*
|
*
|
||||||
@ -56,12 +74,10 @@ public class PointerExtractor implements ValueVisitor<Set<ReconItemIdValue>> {
|
|||||||
*/
|
*/
|
||||||
public Set<ReconItemIdValue> extractPointers(List<SnakGroup> snakGroups) {
|
public Set<ReconItemIdValue> extractPointers(List<SnakGroup> snakGroups) {
|
||||||
Set<ReconItemIdValue> result = new HashSet<>();
|
Set<ReconItemIdValue> result = new HashSet<>();
|
||||||
snakGroups.stream()
|
snakGroups.stream().map(s -> extractPointers(s)).forEach(s -> result.addAll(s));
|
||||||
.map(s -> extractPointers(s))
|
return result;
|
||||||
.forEach(s -> result.addAll(s));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Extracts all the new entities mentioned by this snak group.
|
* Extracts all the new entities mentioned by this snak group.
|
||||||
*
|
*
|
||||||
@ -70,16 +86,14 @@ public class PointerExtractor implements ValueVisitor<Set<ReconItemIdValue>> {
|
|||||||
*/
|
*/
|
||||||
public Set<ReconItemIdValue> extractPointers(SnakGroup snakGroup) {
|
public Set<ReconItemIdValue> extractPointers(SnakGroup snakGroup) {
|
||||||
Set<ReconItemIdValue> result = new HashSet<>();
|
Set<ReconItemIdValue> result = new HashSet<>();
|
||||||
snakGroup.getSnaks().stream()
|
snakGroup.getSnaks().stream().map(s -> extractPointers(s)).forEach(s -> result.addAll(s));
|
||||||
.map(s -> extractPointers(s))
|
return result;
|
||||||
.forEach(s -> result.addAll(s));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts all new entities mentioned by this snak group.
|
* Extracts all new entities mentioned by this snak group. Currently there will
|
||||||
* Currently there will be at most one: the target of the snak
|
* be at most one: the target of the snak (as property ids cannot be new for
|
||||||
* (as property ids cannot be new for now).
|
* now).
|
||||||
*
|
*
|
||||||
* @param snak
|
* @param snak
|
||||||
* @return
|
* @return
|
||||||
@ -90,7 +104,7 @@ public class PointerExtractor implements ValueVisitor<Set<ReconItemIdValue>> {
|
|||||||
result.addAll(extractPointers(snak.getValue()));
|
result.addAll(extractPointers(snak.getValue()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts any new entity from the value.
|
* Extracts any new entity from the value.
|
||||||
*
|
*
|
||||||
@ -115,9 +129,9 @@ public class PointerExtractor implements ValueVisitor<Set<ReconItemIdValue>> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ReconItemIdValue> visit(EntityIdValue value) {
|
public Set<ReconItemIdValue> visit(EntityIdValue value) {
|
||||||
if(ReconItemIdValue.class.isInstance(value)) {
|
if (ReconItemIdValue.class.isInstance(value)) {
|
||||||
ReconItemIdValue recon = (ReconItemIdValue)value;
|
ReconItemIdValue recon = (ReconItemIdValue) value;
|
||||||
if(recon.isNew()) {
|
if (recon.isNew()) {
|
||||||
return Collections.singleton(recon);
|
return Collections.singleton(recon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +160,7 @@ public class PointerExtractor implements ValueVisitor<Set<ReconItemIdValue>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<ReconItemIdValue> visit(TimeValue value) {
|
public Set<ReconItemIdValue> visit(TimeValue value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates.scheduler;
|
package org.openrefine.wikidata.updates.scheduler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -8,49 +31,45 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconEntityIdValue;
|
|
||||||
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
import org.openrefine.wikidata.schema.entityvalues.ReconItemIdValue;
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
import org.openrefine.wikidata.updates.ItemUpdateBuilder;
|
import org.openrefine.wikidata.updates.ItemUpdateBuilder;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
|
|
||||||
|
|
||||||
public class QuickStatementsUpdateScheduler implements UpdateScheduler {
|
public class QuickStatementsUpdateScheduler implements UpdateScheduler {
|
||||||
|
|
||||||
private PointerExtractor extractor = new PointerExtractor();
|
private PointerExtractor extractor = new PointerExtractor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This map holds for each new entity id value a list of updates
|
* This map holds for each new entity id value a list of updates that refer to
|
||||||
* that refer to this id (and should hence be scheduled right after
|
* this id (and should hence be scheduled right after creation of that entity).
|
||||||
* creation of that entity).
|
|
||||||
*/
|
*/
|
||||||
private Map<ItemIdValue, UpdateSequence> pointerUpdates;
|
private Map<ItemIdValue, UpdateSequence> pointerUpdates;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This contains all updates which do not refer to any new entity
|
* This contains all updates which do not refer to any new entity apart from
|
||||||
* apart from possibly the subject, in the order that they were supplied to us.
|
* possibly the subject, in the order that they were supplied to us.
|
||||||
*/
|
*/
|
||||||
private UpdateSequence pointerFreeUpdates;
|
private UpdateSequence pointerFreeUpdates;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Separates out the statements which refer to new items from the rest
|
* Separates out the statements which refer to new items from the rest of the
|
||||||
* of the update. The resulting updates are stored in {@link referencingUpdates}
|
* update. The resulting updates are stored in {@link referencingUpdates} and
|
||||||
* and {@link updatesWithoutReferences}.
|
* {@link updatesWithoutReferences}.
|
||||||
*
|
*
|
||||||
* @param update
|
* @param update
|
||||||
* @throws ImpossibleSchedulingException
|
* @throws ImpossibleSchedulingException
|
||||||
* if two new item ids are referred to in the same statement
|
* if two new item ids are referred to in the same statement
|
||||||
*/
|
*/
|
||||||
protected void splitUpdate(ItemUpdate update) throws ImpossibleSchedulingException {
|
protected void splitUpdate(ItemUpdate update)
|
||||||
|
throws ImpossibleSchedulingException {
|
||||||
ItemUpdateBuilder remainingUpdateBuilder = new ItemUpdateBuilder(update.getItemId())
|
ItemUpdateBuilder remainingUpdateBuilder = new ItemUpdateBuilder(update.getItemId())
|
||||||
.addLabels(update.getLabels())
|
.addLabels(update.getLabels()).addDescriptions(update.getDescriptions()).addAliases(update.getAliases())
|
||||||
.addDescriptions(update.getDescriptions())
|
|
||||||
.addAliases(update.getAliases())
|
|
||||||
.deleteStatements(update.getDeletedStatements());
|
.deleteStatements(update.getDeletedStatements());
|
||||||
Map<ItemIdValue, ItemUpdateBuilder> referencingUpdates = new HashMap<>();
|
Map<ItemIdValue, ItemUpdateBuilder> referencingUpdates = new HashMap<>();
|
||||||
|
|
||||||
for(Statement statement : update.getAddedStatements()) {
|
for (Statement statement : update.getAddedStatements()) {
|
||||||
Set<ReconItemIdValue> pointers = extractor.extractPointers(statement);
|
Set<ReconItemIdValue> pointers = extractor.extractPointers(statement);
|
||||||
if (pointers.isEmpty()) {
|
if (pointers.isEmpty()) {
|
||||||
remainingUpdateBuilder.addStatement(statement);
|
remainingUpdateBuilder.addStatement(statement);
|
||||||
@ -68,14 +87,14 @@ public class QuickStatementsUpdateScheduler implements UpdateScheduler {
|
|||||||
throw new ImpossibleSchedulingException();
|
throw new ImpossibleSchedulingException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the update that is not referring to anything to the schedule
|
// Add the update that is not referring to anything to the schedule
|
||||||
ItemUpdate pointerFree = remainingUpdateBuilder.build();
|
ItemUpdate pointerFree = remainingUpdateBuilder.build();
|
||||||
if (!pointerFree.isNull()) {
|
if (!pointerFree.isNull()) {
|
||||||
pointerFreeUpdates.add(pointerFree);
|
pointerFreeUpdates.add(pointerFree);
|
||||||
}
|
}
|
||||||
// Add the other updates to the map
|
// Add the other updates to the map
|
||||||
for(Entry<ItemIdValue, ItemUpdateBuilder> entry : referencingUpdates.entrySet()) {
|
for (Entry<ItemIdValue, ItemUpdateBuilder> entry : referencingUpdates.entrySet()) {
|
||||||
ItemUpdate pointerUpdate = entry.getValue().build();
|
ItemUpdate pointerUpdate = entry.getValue().build();
|
||||||
UpdateSequence pointerUpdatesForKey = pointerUpdates.get(entry.getKey());
|
UpdateSequence pointerUpdatesForKey = pointerUpdates.get(entry.getKey());
|
||||||
if (pointerUpdatesForKey == null) {
|
if (pointerUpdatesForKey == null) {
|
||||||
@ -87,18 +106,19 @@ public class QuickStatementsUpdateScheduler implements UpdateScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ItemUpdate> schedule(List<ItemUpdate> updates) throws ImpossibleSchedulingException {
|
public List<ItemUpdate> schedule(List<ItemUpdate> updates)
|
||||||
|
throws ImpossibleSchedulingException {
|
||||||
pointerUpdates = new HashMap<>();
|
pointerUpdates = new HashMap<>();
|
||||||
pointerFreeUpdates = new UpdateSequence();
|
pointerFreeUpdates = new UpdateSequence();
|
||||||
|
|
||||||
for(ItemUpdate update : updates) {
|
for (ItemUpdate update : updates) {
|
||||||
splitUpdate(update);
|
splitUpdate(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconstruct
|
// Reconstruct
|
||||||
List<ItemUpdate> fullSchedule = new ArrayList<>();
|
List<ItemUpdate> fullSchedule = new ArrayList<>();
|
||||||
Set<ItemIdValue> mentionedNewEntities = new HashSet<>(pointerUpdates.keySet());
|
Set<ItemIdValue> mentionedNewEntities = new HashSet<>(pointerUpdates.keySet());
|
||||||
for(ItemUpdate update : pointerFreeUpdates.getUpdates()) {
|
for (ItemUpdate update : pointerFreeUpdates.getUpdates()) {
|
||||||
fullSchedule.add(update);
|
fullSchedule.add(update);
|
||||||
UpdateSequence backPointers = pointerUpdates.get(update.getItemId());
|
UpdateSequence backPointers = pointerUpdates.get(update.getItemId());
|
||||||
if (backPointers != null) {
|
if (backPointers != null) {
|
||||||
@ -106,11 +126,11 @@ public class QuickStatementsUpdateScheduler implements UpdateScheduler {
|
|||||||
}
|
}
|
||||||
mentionedNewEntities.remove(update.getItemId());
|
mentionedNewEntities.remove(update.getItemId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create any item that was referred to but untouched
|
// Create any item that was referred to but untouched
|
||||||
// (this is just for the sake of correctness, it would be bad to do that
|
// (this is just for the sake of correctness, it would be bad to do that
|
||||||
// as the items would remain blank in this batch).
|
// as the items would remain blank in this batch).
|
||||||
for(ItemIdValue missingId : mentionedNewEntities) {
|
for (ItemIdValue missingId : mentionedNewEntities) {
|
||||||
fullSchedule.add(new ItemUpdateBuilder(missingId).build());
|
fullSchedule.add(new ItemUpdateBuilder(missingId).build());
|
||||||
fullSchedule.addAll(pointerUpdates.get(missingId).getUpdates());
|
fullSchedule.addAll(pointerUpdates.get(missingId).getUpdates());
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates.scheduler;
|
package org.openrefine.wikidata.updates.scheduler;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -5,28 +28,26 @@ import java.util.List;
|
|||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A scheduling strategy for item updates.
|
* A scheduling strategy for item updates. Given a list of initial updates, the
|
||||||
* Given a list of initial updates, the scheduler
|
* scheduler reorganizes these updates (possibly splitting them or merging them)
|
||||||
* reorganizes these updates (possibly splitting them
|
* to create a sequence that is suitable for a particular import process.
|
||||||
* or merging them) to create a sequence that is suitable
|
|
||||||
* for a particular import process.
|
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface UpdateScheduler {
|
public interface UpdateScheduler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the scheduling. The initial updates are provided
|
* Performs the scheduling. The initial updates are provided as a list so that
|
||||||
* as a list so that the scheduler can attempt to respect the
|
* the scheduler can attempt to respect the initial order (but no guarantee is
|
||||||
* initial order (but no guarantee is made for that in general).
|
* made for that in general).
|
||||||
*
|
*
|
||||||
* @param updates
|
* @param updates
|
||||||
* the updates to schedule
|
* the updates to schedule
|
||||||
* @return
|
* @return the reorganized updates
|
||||||
* the reorganized updates
|
* @throws ImpossibleSchedulingException
|
||||||
* @throws ImpossibleSchedulingException
|
* when the scheduler cannot cope with a particular edit plan.
|
||||||
* when the scheduler cannot cope with a particular edit plan.
|
|
||||||
*/
|
*/
|
||||||
public List<ItemUpdate> schedule(List<ItemUpdate> updates) throws ImpossibleSchedulingException;
|
public List<ItemUpdate> schedule(List<ItemUpdate> updates)
|
||||||
|
throws ImpossibleSchedulingException;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates.scheduler;
|
package org.openrefine.wikidata.updates.scheduler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -10,12 +33,13 @@ import org.openrefine.wikidata.updates.ItemUpdate;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to store a list of updates where each subject
|
* Helper class to store a list of updates where each subject appears at most
|
||||||
* appears at most once. It preserves order of insertion.
|
* once. It preserves order of insertion.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*/
|
*/
|
||||||
public class UpdateSequence {
|
public class UpdateSequence {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of updates stored by this container
|
* The list of updates stored by this container
|
||||||
*/
|
*/
|
||||||
@ -24,16 +48,16 @@ public class UpdateSequence {
|
|||||||
* An index to keep track of where each item is touched in the sequence
|
* An index to keep track of where each item is touched in the sequence
|
||||||
*/
|
*/
|
||||||
private Map<ItemIdValue, Integer> index = new HashMap<>();
|
private Map<ItemIdValue, Integer> index = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new update to the list, merging it with any existing
|
* Adds a new update to the list, merging it with any existing one with the same
|
||||||
* one with the same subject.
|
* subject.
|
||||||
*
|
*
|
||||||
* @param update
|
* @param update
|
||||||
*/
|
*/
|
||||||
public void add(ItemUpdate update) {
|
public void add(ItemUpdate update) {
|
||||||
ItemIdValue subject = update.getItemId();
|
ItemIdValue subject = update.getItemId();
|
||||||
if(index.containsKey(subject)) {
|
if (index.containsKey(subject)) {
|
||||||
int i = index.get(subject);
|
int i = index.get(subject);
|
||||||
ItemUpdate oldUpdate = updates.get(i);
|
ItemUpdate oldUpdate = updates.get(i);
|
||||||
updates.set(i, oldUpdate.merge(update));
|
updates.set(i, oldUpdate.merge(update));
|
||||||
@ -42,18 +66,18 @@ public class UpdateSequence {
|
|||||||
updates.add(update);
|
updates.add(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the list of merged updates
|
* @return the list of merged updates
|
||||||
*/
|
*/
|
||||||
public List<ItemUpdate> getUpdates() {
|
public List<ItemUpdate> getUpdates() {
|
||||||
return updates;
|
return updates;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the set of touched subjects
|
* @return the set of touched subjects
|
||||||
*/
|
*/
|
||||||
public Set<ItemIdValue> getSubjects() {
|
public Set<ItemIdValue> getSubjects() {
|
||||||
return index.keySet();
|
return index.keySet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.updates.scheduler;
|
package org.openrefine.wikidata.updates.scheduler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -15,33 +38,32 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
|||||||
/**
|
/**
|
||||||
* A simple scheduler for batches commited via the Wikibase API.
|
* A simple scheduler for batches commited via the Wikibase API.
|
||||||
*
|
*
|
||||||
* The strategy is quite simple and makes at most two edits
|
* The strategy is quite simple and makes at most two edits per touched item
|
||||||
* per touched item (which is not minimal though). Each update
|
* (which is not minimal though). Each update is split between statements making
|
||||||
* is split between statements making references to new items,
|
* references to new items, and statements not making these references. All
|
||||||
* and statements not making these references. All updates with no
|
* updates with no references to new items are done first (which creates all new
|
||||||
* references to new items are done first (which creates all new
|
|
||||||
* items), then all other updates are done.
|
* items), then all other updates are done.
|
||||||
*
|
*
|
||||||
* @author Antonin Delpeuch
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class WikibaseAPIUpdateScheduler implements UpdateScheduler {
|
public class WikibaseAPIUpdateScheduler implements UpdateScheduler {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The first part of updates: the ones which create new items
|
* The first part of updates: the ones which create new items without referring
|
||||||
* without referring to any other new item.
|
* to any other new item.
|
||||||
*/
|
*/
|
||||||
private UpdateSequence pointerFreeUpdates;
|
private UpdateSequence pointerFreeUpdates;
|
||||||
/**
|
/**
|
||||||
* The second part of the updates: all existing items, plus
|
* The second part of the updates: all existing items, plus all parts of new
|
||||||
* all parts of new items that refer to other new items.
|
* items that refer to other new items.
|
||||||
*/
|
*/
|
||||||
private UpdateSequence pointerFullUpdates;
|
private UpdateSequence pointerFullUpdates;
|
||||||
/**
|
/**
|
||||||
* The set of all new items referred to in the whole batch.
|
* The set of all new items referred to in the whole batch.
|
||||||
*/
|
*/
|
||||||
private Set<ItemIdValue> allPointers;
|
private Set<ItemIdValue> allPointers;
|
||||||
|
|
||||||
private PointerExtractor extractor = new PointerExtractor();
|
private PointerExtractor extractor = new PointerExtractor();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -50,22 +72,20 @@ public class WikibaseAPIUpdateScheduler implements UpdateScheduler {
|
|||||||
pointerFreeUpdates = new UpdateSequence();
|
pointerFreeUpdates = new UpdateSequence();
|
||||||
pointerFullUpdates = new UpdateSequence();
|
pointerFullUpdates = new UpdateSequence();
|
||||||
allPointers = new HashSet<>();
|
allPointers = new HashSet<>();
|
||||||
|
|
||||||
for(ItemUpdate update : updates) {
|
for (ItemUpdate update : updates) {
|
||||||
splitUpdate(update);
|
splitUpdate(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 1: add all the pointer free updates
|
// Part 1: add all the pointer free updates
|
||||||
result.addAll(pointerFreeUpdates.getUpdates());
|
result.addAll(pointerFreeUpdates.getUpdates());
|
||||||
|
|
||||||
// Part 1': add the remaining new items that have not been touched
|
// Part 1': add the remaining new items that have not been touched
|
||||||
Set<ItemIdValue> unseenPointers = new HashSet<>(allPointers);
|
Set<ItemIdValue> unseenPointers = new HashSet<>(allPointers);
|
||||||
unseenPointers.removeAll(pointerFreeUpdates.getSubjects());
|
unseenPointers.removeAll(pointerFreeUpdates.getSubjects());
|
||||||
|
|
||||||
result.addAll(unseenPointers.stream()
|
result.addAll(unseenPointers.stream().map(e -> new ItemUpdateBuilder(e).build()).collect(Collectors.toList()));
|
||||||
.map(e -> new ItemUpdateBuilder(e).build())
|
|
||||||
.collect(Collectors.toList()));
|
|
||||||
|
|
||||||
// Part 2: add all the pointer full updates
|
// Part 2: add all the pointer full updates
|
||||||
result.addAll(pointerFullUpdates.getUpdates());
|
result.addAll(pointerFullUpdates.getUpdates());
|
||||||
|
|
||||||
@ -74,17 +94,16 @@ public class WikibaseAPIUpdateScheduler implements UpdateScheduler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Splits an update into two parts
|
* Splits an update into two parts
|
||||||
|
*
|
||||||
* @param update
|
* @param update
|
||||||
*/
|
*/
|
||||||
protected void splitUpdate(ItemUpdate update) {
|
protected void splitUpdate(ItemUpdate update) {
|
||||||
ItemUpdateBuilder pointerFreeBuilder = new ItemUpdateBuilder(update.getItemId())
|
ItemUpdateBuilder pointerFreeBuilder = new ItemUpdateBuilder(update.getItemId()).addLabels(update.getLabels())
|
||||||
.addLabels(update.getLabels())
|
.addDescriptions(update.getDescriptions()).addAliases(update.getAliases())
|
||||||
.addDescriptions(update.getDescriptions())
|
|
||||||
.addAliases(update.getAliases())
|
|
||||||
.deleteStatements(update.getDeletedStatements());
|
.deleteStatements(update.getDeletedStatements());
|
||||||
ItemUpdateBuilder pointerFullBuilder = new ItemUpdateBuilder(update.getItemId());
|
ItemUpdateBuilder pointerFullBuilder = new ItemUpdateBuilder(update.getItemId());
|
||||||
|
|
||||||
for(Statement statement : update.getAddedStatements()) {
|
for (Statement statement : update.getAddedStatements()) {
|
||||||
Set<ReconItemIdValue> pointers = extractor.extractPointers(statement);
|
Set<ReconItemIdValue> pointers = extractor.extractPointers(statement);
|
||||||
if (pointers.isEmpty()) {
|
if (pointers.isEmpty()) {
|
||||||
pointerFreeBuilder.addStatement(statement);
|
pointerFreeBuilder.addStatement(statement);
|
||||||
@ -93,8 +112,8 @@ public class WikibaseAPIUpdateScheduler implements UpdateScheduler {
|
|||||||
}
|
}
|
||||||
allPointers.addAll(pointers);
|
allPointers.addAll(pointers);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(update.isNew()) {
|
if (update.isNew()) {
|
||||||
// If the update is new, we might need to split it
|
// If the update is new, we might need to split it
|
||||||
// in two (if it refers to any other new entity).
|
// in two (if it refers to any other new entity).
|
||||||
ItemUpdate pointerFree = pointerFreeBuilder.build();
|
ItemUpdate pointerFree = pointerFreeBuilder.build();
|
||||||
@ -111,5 +130,5 @@ public class WikibaseAPIUpdateScheduler implements UpdateScheduler {
|
|||||||
pointerFullUpdates.add(update);
|
pointerFullUpdates.add(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.utils;
|
package org.openrefine.wikidata.utils;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -14,42 +37,42 @@ import com.google.common.cache.CacheLoader;
|
|||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
|
|
||||||
public class EntityCache {
|
public class EntityCache {
|
||||||
|
|
||||||
private static EntityCache _entityCache = new EntityCache();
|
private static EntityCache _entityCache = new EntityCache();
|
||||||
|
|
||||||
private LoadingCache<String, EntityDocument> _cache = null;
|
private LoadingCache<String, EntityDocument> _cache = null;
|
||||||
private WikibaseDataFetcher _fetcher;
|
private WikibaseDataFetcher _fetcher;
|
||||||
|
|
||||||
private EntityCache() {
|
private EntityCache() {
|
||||||
ApiConnection connection = ApiConnection.getWikidataApiConnection();
|
ApiConnection connection = ApiConnection.getWikidataApiConnection();
|
||||||
_fetcher = new WikibaseDataFetcher(connection, Datamodel.SITE_WIKIDATA);
|
_fetcher = new WikibaseDataFetcher(connection, Datamodel.SITE_WIKIDATA);
|
||||||
|
|
||||||
_cache = CacheBuilder.newBuilder()
|
_cache = CacheBuilder.newBuilder().maximumSize(4096).expireAfterWrite(1, TimeUnit.HOURS)
|
||||||
.maximumSize(4096)
|
.build(new CacheLoader<String, EntityDocument>() {
|
||||||
.expireAfterWrite(1, TimeUnit.HOURS)
|
|
||||||
.build(
|
public EntityDocument load(String entityId)
|
||||||
new CacheLoader<String, EntityDocument>() {
|
throws Exception {
|
||||||
public EntityDocument load(String entityId) throws Exception {
|
EntityDocument doc = _fetcher.getEntityDocument(entityId);
|
||||||
EntityDocument doc = _fetcher.getEntityDocument(entityId);
|
if (doc != null) {
|
||||||
if (doc != null) {
|
return doc;
|
||||||
return doc;
|
} else {
|
||||||
} else {
|
throw new MediaWikiApiErrorException("400", "Unknown entity id \"" + entityId + "\"");
|
||||||
throw new MediaWikiApiErrorException("400", "Unknown entity id \""+entityId+"\"");
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityDocument get(EntityIdValue id) {
|
public EntityDocument get(EntityIdValue id) {
|
||||||
return _cache.apply(id.getId());
|
return _cache.apply(id.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EntityCache getEntityCache() {
|
public static EntityCache getEntityCache() {
|
||||||
if (_entityCache == null) {
|
if (_entityCache == null) {
|
||||||
_entityCache = new EntityCache();
|
_entityCache = new EntityCache();
|
||||||
}
|
}
|
||||||
return _entityCache;
|
return _entityCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EntityDocument getEntityDocument(EntityIdValue id) {
|
public static EntityDocument getEntityDocument(EntityIdValue id) {
|
||||||
return getEntityCache().get(id);
|
return getEntityCache().get(id);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.utils;
|
package org.openrefine.wikidata.utils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -6,25 +29,27 @@ import java.io.StringReader;
|
|||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
public class FirstLinesExtractor {
|
public class FirstLinesExtractor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the first n lines of a given string
|
* Returns the first n lines of a given string
|
||||||
|
*
|
||||||
* @param content
|
* @param content
|
||||||
* the content, where lines are separated by '\n'
|
* the content, where lines are separated by '\n'
|
||||||
* @param nbLines
|
* @param nbLines
|
||||||
* the number of lines to extract
|
* the number of lines to extract
|
||||||
* @return
|
* @return the first lines of the string
|
||||||
* the first lines of the string
|
* @throws IOException
|
||||||
* @throws IOException
|
|
||||||
*/
|
*/
|
||||||
public static String extractFirstLines(String content, int nbLines) throws IOException {
|
public static String extractFirstLines(String content, int nbLines)
|
||||||
|
throws IOException {
|
||||||
StringWriter stringWriter = new StringWriter();
|
StringWriter stringWriter = new StringWriter();
|
||||||
LineNumberReader reader = new LineNumberReader(new StringReader(content));
|
LineNumberReader reader = new LineNumberReader(new StringReader(content));
|
||||||
|
|
||||||
// Only keep the first 50 lines
|
// Only keep the first 50 lines
|
||||||
reader.setLineNumber(0);
|
reader.setLineNumber(0);
|
||||||
String line = reader.readLine();
|
String line = reader.readLine();
|
||||||
for(int i = 1; i != nbLines && line != null; i++) {
|
for (int i = 1; i != nbLines && line != null; i++) {
|
||||||
stringWriter.write(line+"\n");
|
stringWriter.write(line + "\n");
|
||||||
line = reader.readLine();
|
line = reader.readLine();
|
||||||
}
|
}
|
||||||
if (reader.getLineNumber() == nbLines) {
|
if (reader.getLineNumber() == nbLines) {
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.utils;
|
package org.openrefine.wikidata.utils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -16,13 +39,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import com.google.refine.Jsonizable;
|
import com.google.refine.Jsonizable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is inefficient because it serializes the
|
* This class is inefficient because it serializes the object to string and then
|
||||||
* object to string and then deserializes it back. Unfortunately,
|
* deserializes it back. Unfortunately, this is the only simple way to bridge
|
||||||
* this is the only simple way to bridge Jackson to org.json.
|
* Jackson to org.json. This conversion should be removed when (if ?) we migrate
|
||||||
* This conversion should be removed when (if ?) we migrate OpenRefine
|
* OpenRefine a better JSON library.
|
||||||
* a better JSON library.
|
|
||||||
*
|
*
|
||||||
* @author antonin
|
* @author Antonin Delpeuch
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@ -38,8 +60,9 @@ public abstract class JacksonJsonizable implements Jsonizable {
|
|||||||
throw new JSONException(e.toString());
|
throw new JSONException(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T fromJSONClass(JSONObject obj, Class<T> klass) throws JSONException {
|
public static <T> T fromJSONClass(JSONObject obj, Class<T> klass)
|
||||||
|
throws JSONException {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
String json = obj.toString();
|
String json = obj.toString();
|
||||||
try {
|
try {
|
||||||
@ -50,7 +73,7 @@ public abstract class JacksonJsonizable implements Jsonizable {
|
|||||||
throw new JSONException(e.toString());
|
throw new JSONException(e.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new JSONException(e.toString());
|
throw new JSONException(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,73 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import java.io.StringWriter;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.openrefine.wikidata.testing.TestingData;
|
|
||||||
import org.testng.Assert;
|
|
||||||
import org.testng.annotations.BeforeMethod;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.openrefine.wikidata.testing.TestingData;
|
||||||
|
import org.testng.Assert;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
|
||||||
import com.google.refine.commands.Command;
|
import com.google.refine.commands.Command;
|
||||||
import com.google.refine.model.Project;
|
import com.google.refine.model.Project;
|
||||||
import com.google.refine.tests.RefineTest;
|
import com.google.refine.tests.RefineTest;
|
||||||
import com.google.refine.util.ParsingUtilities;
|
|
||||||
|
|
||||||
public abstract class CommandTest extends RefineTest {
|
public abstract class CommandTest extends RefineTest {
|
||||||
|
|
||||||
protected Project project = null;
|
protected Project project = null;
|
||||||
protected HttpServletRequest request = null;
|
protected HttpServletRequest request = null;
|
||||||
protected HttpServletResponse response = null;
|
protected HttpServletResponse response = null;
|
||||||
protected StringWriter writer = null;
|
protected StringWriter writer = null;
|
||||||
|
|
||||||
protected Command command = null;
|
protected Command command = null;
|
||||||
|
|
||||||
@BeforeMethod(alwaysRun = true)
|
@BeforeMethod(alwaysRun = true)
|
||||||
public void setUpProject() throws JSONException {
|
public void setUpProject()
|
||||||
|
throws JSONException {
|
||||||
project = createCSVProject(TestingData.inceptionWithNewCsv);
|
project = createCSVProject(TestingData.inceptionWithNewCsv);
|
||||||
TestingData.reconcileInceptionCells(project);
|
TestingData.reconcileInceptionCells(project);
|
||||||
request = mock(HttpServletRequest.class);
|
request = mock(HttpServletRequest.class);
|
||||||
response = mock(HttpServletResponse.class);
|
response = mock(HttpServletResponse.class);
|
||||||
writer = new StringWriter();
|
writer = new StringWriter();
|
||||||
PrintWriter printWriter = new PrintWriter(writer);
|
PrintWriter printWriter = new PrintWriter(writer);
|
||||||
|
|
||||||
when(request.getParameter("project")).thenReturn(String.valueOf(project.id));
|
when(request.getParameter("project")).thenReturn(String.valueOf(project.id));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
when(response.getWriter()).thenReturn(printWriter);
|
when(response.getWriter()).thenReturn(printWriter);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,34 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.openrefine.wikidata.testing.TestingData.jsonFromFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@ -8,29 +37,24 @@ import org.openrefine.wikidata.testing.TestingData;
|
|||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import com.google.refine.util.ParsingUtilities;
|
import com.google.refine.util.ParsingUtilities;
|
||||||
|
|
||||||
import static org.openrefine.wikidata.testing.TestingData.jsonFromFile;
|
|
||||||
|
|
||||||
public class PreviewWikibaseSchemaCommandTest extends SchemaCommandTest {
|
public class PreviewWikibaseSchemaCommandTest extends SchemaCommandTest {
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void SetUp() throws JSONException {
|
public void SetUp()
|
||||||
|
throws JSONException {
|
||||||
command = new PreviewWikibaseSchemaCommand();
|
command = new PreviewWikibaseSchemaCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidSchema() throws JSONException, IOException, ServletException {
|
public void testValidSchema()
|
||||||
|
throws JSONException, IOException, ServletException {
|
||||||
String schemaJson = jsonFromFile("data/schema/inception.json").toString();
|
String schemaJson = jsonFromFile("data/schema/inception.json").toString();
|
||||||
when(request.getParameter("schema")).thenReturn(schemaJson);
|
when(request.getParameter("schema")).thenReturn(schemaJson);
|
||||||
|
|
||||||
command.doPost(request, response);
|
command.doPost(request, response);
|
||||||
|
|
||||||
JSONObject response = ParsingUtilities.evaluateJsonStringToObject(writer.toString());
|
JSONObject response = ParsingUtilities.evaluateJsonStringToObject(writer.toString());
|
||||||
assertEquals(TestingData.inceptionWithNewQS, response.getString("quickstatements"));
|
assertEquals(TestingData.inceptionWithNewQS, response.getString("quickstatements"));
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,54 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import org.testng.annotations.BeforeMethod;
|
import static org.junit.Assert.assertTrue;
|
||||||
import org.testng.annotations.Test;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import static org.openrefine.wikidata.testing.TestingData.jsonFromFile;
|
import static org.openrefine.wikidata.testing.TestingData.jsonFromFile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import static org.mockito.Mockito.when;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
public class SaveWikibaseSchemaCommandTest extends SchemaCommandTest {
|
public class SaveWikibaseSchemaCommandTest extends SchemaCommandTest {
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
this.command = new SaveWikibaseSchemaCommand();
|
this.command = new SaveWikibaseSchemaCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidSchema() throws ServletException, IOException {
|
public void testValidSchema()
|
||||||
|
throws ServletException, IOException {
|
||||||
String schemaJson = jsonFromFile("data/schema/inception.json").toString();
|
String schemaJson = jsonFromFile("data/schema/inception.json").toString();
|
||||||
when(request.getParameter("schema")).thenReturn(schemaJson);
|
when(request.getParameter("schema")).thenReturn(schemaJson);
|
||||||
|
|
||||||
command.doPost(request, response);
|
command.doPost(request, response);
|
||||||
|
|
||||||
assertTrue(writer.toString().contains("\"ok\""));
|
assertTrue(writer.toString().contains("\"ok\""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,28 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.commands;
|
package org.openrefine.wikidata.commands;
|
||||||
|
|
||||||
import org.testng.annotations.BeforeMethod;
|
|
||||||
import org.testng.annotations.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@ -10,20 +30,24 @@ import java.io.IOException;
|
|||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
public abstract class SchemaCommandTest extends CommandTest {
|
public abstract class SchemaCommandTest extends CommandTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoSchema() throws ServletException, IOException {
|
public void testNoSchema()
|
||||||
|
throws ServletException, IOException {
|
||||||
command.doPost(request, response);
|
command.doPost(request, response);
|
||||||
|
|
||||||
assertEquals("{\"status\":\"error\",\"message\":\"No Wikibase schema provided.\"}", writer.toString());
|
assertEquals("{\"status\":\"error\",\"message\":\"No Wikibase schema provided.\"}", writer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidSchema() throws ServletException, IOException {
|
public void testInvalidSchema()
|
||||||
|
throws ServletException, IOException {
|
||||||
when(request.getParameter("schema")).thenReturn("{bogus json");
|
when(request.getParameter("schema")).thenReturn("{bogus json");
|
||||||
command.doPost(request, response);
|
command.doPost(request, response);
|
||||||
|
|
||||||
assertEquals("{\"status\":\"error\",\"message\":\"Wikibase schema could not be parsed.\"}", writer.toString());
|
assertEquals("{\"status\":\"error\",\"message\":\"Wikibase schema could not be parsed.\"}", writer.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import org.openrefine.wikidata.testing.TestingData;
|
import org.openrefine.wikidata.testing.TestingData;
|
||||||
@ -31,14 +54,13 @@ import java.util.stream.Collectors;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
|
|
||||||
|
|
||||||
public class EditBatchProcessorTest extends RefineTest {
|
public class EditBatchProcessorTest extends RefineTest {
|
||||||
|
|
||||||
private WikibaseDataFetcher fetcher = null;
|
private WikibaseDataFetcher fetcher = null;
|
||||||
private WikibaseDataEditor editor = null;
|
private WikibaseDataEditor editor = null;
|
||||||
private NewItemLibrary library = null;
|
private NewItemLibrary library = null;
|
||||||
private String summary = "my fantastic edits";
|
private String summary = "my fantastic edits";
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
fetcher = mock(WikibaseDataFetcher.class);
|
fetcher = mock(WikibaseDataFetcher.class);
|
||||||
@ -46,33 +68,29 @@ public class EditBatchProcessorTest extends RefineTest {
|
|||||||
editor.disableEditing(); // just in case we got mocking wrong…
|
editor.disableEditing(); // just in case we got mocking wrong…
|
||||||
library = new NewItemLibrary();
|
library = new NewItemLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNewItem() throws InterruptedException, MediaWikiApiErrorException, IOException {
|
public void testNewItem()
|
||||||
|
throws InterruptedException, MediaWikiApiErrorException, IOException {
|
||||||
List<ItemUpdate> batch = new ArrayList<>();
|
List<ItemUpdate> batch = new ArrayList<>();
|
||||||
batch.add(new ItemUpdateBuilder(TestingData.existingId)
|
batch.add(new ItemUpdateBuilder(TestingData.existingId)
|
||||||
.addAlias(Datamodel.makeMonolingualTextValue("my new alias", "en"))
|
.addAlias(Datamodel.makeMonolingualTextValue("my new alias", "en"))
|
||||||
.addStatement(TestingData.generateStatement(TestingData.existingId, TestingData.newIdA))
|
.addStatement(TestingData.generateStatement(TestingData.existingId, TestingData.newIdA)).build());
|
||||||
.build());
|
|
||||||
MonolingualTextValue label = Datamodel.makeMonolingualTextValue("better label", "en");
|
MonolingualTextValue label = Datamodel.makeMonolingualTextValue("better label", "en");
|
||||||
batch.add(new ItemUpdateBuilder(TestingData.newIdA)
|
batch.add(new ItemUpdateBuilder(TestingData.newIdA).addAlias(label).build());
|
||||||
.addAlias(label)
|
|
||||||
.build());
|
|
||||||
|
|
||||||
// Plan expected edits
|
// Plan expected edits
|
||||||
ItemDocument existingItem = ItemDocumentBuilder.forItemId(TestingData.existingId)
|
ItemDocument existingItem = ItemDocumentBuilder.forItemId(TestingData.existingId)
|
||||||
.withLabel(Datamodel.makeMonolingualTextValue("pomme", "fr"))
|
.withLabel(Datamodel.makeMonolingualTextValue("pomme", "fr"))
|
||||||
.withDescription(Datamodel.makeMonolingualTextValue("fruit délicieux", "fr"))
|
.withDescription(Datamodel.makeMonolingualTextValue("fruit délicieux", "fr")).build();
|
||||||
.build();
|
|
||||||
when(fetcher.getEntityDocuments(Collections.singletonList(TestingData.existingId.getId())))
|
when(fetcher.getEntityDocuments(Collections.singletonList(TestingData.existingId.getId())))
|
||||||
.thenReturn(Collections.singletonMap(TestingData.existingId.getId(), existingItem));
|
.thenReturn(Collections.singletonMap(TestingData.existingId.getId(), existingItem));
|
||||||
|
|
||||||
ItemDocument expectedNewItem = ItemDocumentBuilder.forItemId(TestingData.newIdA)
|
ItemDocument expectedNewItem = ItemDocumentBuilder.forItemId(TestingData.newIdA).withLabel(label).build();
|
||||||
.withLabel(label).build();
|
|
||||||
ItemDocument createdNewItem = ItemDocumentBuilder.forItemId(Datamodel.makeWikidataItemIdValue("Q1234"))
|
ItemDocument createdNewItem = ItemDocumentBuilder.forItemId(Datamodel.makeWikidataItemIdValue("Q1234"))
|
||||||
.withLabel(label).withRevisionId(37828L).build();
|
.withLabel(label).withRevisionId(37828L).build();
|
||||||
when(editor.createItemDocument(expectedNewItem, summary)).thenReturn(createdNewItem);
|
when(editor.createItemDocument(expectedNewItem, summary)).thenReturn(createdNewItem);
|
||||||
|
|
||||||
EditBatchProcessor processor = new EditBatchProcessor(fetcher, editor, batch, library, summary, 50);
|
EditBatchProcessor processor = new EditBatchProcessor(fetcher, editor, batch, library, summary, 50);
|
||||||
assertEquals(2, processor.remainingEdits());
|
assertEquals(2, processor.remainingEdits());
|
||||||
assertEquals(0, processor.progress());
|
assertEquals(0, processor.progress());
|
||||||
@ -85,67 +103,63 @@ public class EditBatchProcessorTest extends RefineTest {
|
|||||||
processor.performEdit(); // does not do anything
|
processor.performEdit(); // does not do anything
|
||||||
assertEquals(0, processor.remainingEdits());
|
assertEquals(0, processor.remainingEdits());
|
||||||
assertEquals(100, processor.progress());
|
assertEquals(100, processor.progress());
|
||||||
|
|
||||||
NewItemLibrary expectedLibrary = new NewItemLibrary();
|
NewItemLibrary expectedLibrary = new NewItemLibrary();
|
||||||
expectedLibrary.setQid(1234L, "Q1234");
|
expectedLibrary.setQid(1234L, "Q1234");
|
||||||
assertEquals(expectedLibrary, library);
|
assertEquals(expectedLibrary, library);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleBatches() throws MediaWikiApiErrorException, InterruptedException, IOException {
|
public void testMultipleBatches()
|
||||||
|
throws MediaWikiApiErrorException, InterruptedException, IOException {
|
||||||
// Prepare test data
|
// Prepare test data
|
||||||
MonolingualTextValue description = Datamodel.makeMonolingualTextValue("village in Nepal", "en");
|
MonolingualTextValue description = Datamodel.makeMonolingualTextValue("village in Nepal", "en");
|
||||||
List<String> ids = new ArrayList<>();
|
List<String> ids = new ArrayList<>();
|
||||||
for(int i = 124; i < 190; i++) {
|
for (int i = 124; i < 190; i++) {
|
||||||
ids.add("Q"+String.valueOf(i));
|
ids.add("Q" + String.valueOf(i));
|
||||||
}
|
}
|
||||||
List<ItemIdValue> qids = ids.stream()
|
List<ItemIdValue> qids = ids.stream().map(e -> Datamodel.makeWikidataItemIdValue(e))
|
||||||
.map(e -> Datamodel.makeWikidataItemIdValue(e))
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
List<ItemUpdate> batch = qids.stream()
|
List<ItemUpdate> batch = qids.stream()
|
||||||
.map(qid -> new ItemUpdateBuilder(qid)
|
.map(qid -> new ItemUpdateBuilder(qid).addDescription(description).build())
|
||||||
.addDescription(description)
|
|
||||||
.build())
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
int batchSize = 50;
|
int batchSize = 50;
|
||||||
List<ItemDocument> fullBatch = qids.stream()
|
List<ItemDocument> fullBatch = qids.stream()
|
||||||
.map(qid -> ItemDocumentBuilder.forItemId(qid)
|
.map(qid -> ItemDocumentBuilder.forItemId(qid)
|
||||||
.withStatement(TestingData.generateStatement(qid, TestingData.existingId))
|
.withStatement(TestingData.generateStatement(qid, TestingData.existingId)).build())
|
||||||
.build())
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
List<ItemDocument> firstBatch = fullBatch.subList(0, batchSize);
|
List<ItemDocument> firstBatch = fullBatch.subList(0, batchSize);
|
||||||
List<ItemDocument> secondBatch = fullBatch.subList(batchSize, fullBatch.size());
|
List<ItemDocument> secondBatch = fullBatch.subList(batchSize, fullBatch.size());
|
||||||
|
|
||||||
when(fetcher.getEntityDocuments(toQids(firstBatch))).thenReturn(toMap(firstBatch));
|
when(fetcher.getEntityDocuments(toQids(firstBatch))).thenReturn(toMap(firstBatch));
|
||||||
when(fetcher.getEntityDocuments(toQids(secondBatch))).thenReturn(toMap(secondBatch));
|
when(fetcher.getEntityDocuments(toQids(secondBatch))).thenReturn(toMap(secondBatch));
|
||||||
|
|
||||||
// Run edits
|
// Run edits
|
||||||
EditBatchProcessor processor = new EditBatchProcessor(fetcher, editor, batch, library, summary, batchSize);
|
EditBatchProcessor processor = new EditBatchProcessor(fetcher, editor, batch, library, summary, batchSize);
|
||||||
assertEquals(0, processor.progress());
|
assertEquals(0, processor.progress());
|
||||||
for(int i = 124; i < 190; i++) {
|
for (int i = 124; i < 190; i++) {
|
||||||
assertEquals(processor.remainingEdits(), 190-i);
|
assertEquals(processor.remainingEdits(), 190 - i);
|
||||||
processor.performEdit();
|
processor.performEdit();
|
||||||
}
|
}
|
||||||
assertEquals(0, processor.remainingEdits());
|
assertEquals(0, processor.remainingEdits());
|
||||||
assertEquals(100, processor.progress());
|
assertEquals(100, processor.progress());
|
||||||
|
|
||||||
// Check result
|
// Check result
|
||||||
assertEquals(new NewItemLibrary(), library);
|
assertEquals(new NewItemLibrary(), library);
|
||||||
verify(fetcher, times(1)).getEntityDocuments(toQids(firstBatch));
|
verify(fetcher, times(1)).getEntityDocuments(toQids(firstBatch));
|
||||||
verify(fetcher, times(1)).getEntityDocuments(toQids(secondBatch));
|
verify(fetcher, times(1)).getEntityDocuments(toQids(secondBatch));
|
||||||
for(ItemDocument doc : fullBatch) {
|
for (ItemDocument doc : fullBatch) {
|
||||||
verify(editor, times(1)).updateTermsStatements(doc, Collections.emptyList(),
|
verify(editor, times(1)).updateTermsStatements(doc, Collections.emptyList(),
|
||||||
Collections.singletonList(description), Collections.emptyList(), Collections.emptyList(),
|
Collections.singletonList(description), Collections.emptyList(), Collections.emptyList(),
|
||||||
Collections.emptyList(), Collections.emptyList(), summary);
|
Collections.emptyList(), Collections.emptyList(), summary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, EntityDocument> toMap(List<ItemDocument> docs) {
|
private Map<String, EntityDocument> toMap(List<ItemDocument> docs) {
|
||||||
return docs.stream()
|
return docs.stream().collect(Collectors.toMap(doc -> doc.getItemId().getId(), doc -> doc));
|
||||||
.collect(Collectors.toMap(doc -> doc.getItemId().getId(), doc -> doc));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> toQids(List<ItemDocument> docs) {
|
private List<String> toQids(List<ItemDocument> docs) {
|
||||||
return docs.stream().map(doc -> doc.getItemId().getId()).collect(Collectors.toList());
|
return docs.stream().map(doc -> doc.getItemId().getId()).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -13,20 +36,21 @@ import com.google.refine.model.Recon;
|
|||||||
import com.google.refine.tests.RefineTest;
|
import com.google.refine.tests.RefineTest;
|
||||||
|
|
||||||
public class NewItemLibraryTest extends RefineTest {
|
public class NewItemLibraryTest extends RefineTest {
|
||||||
|
|
||||||
private NewItemLibrary library;
|
private NewItemLibrary library;
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
library = new NewItemLibrary();
|
library = new NewItemLibrary();
|
||||||
library.setQid(1234L, "Q345");
|
library.setQid(1234L, "Q345");
|
||||||
library.setQid(3289L, "Q384");
|
library.setQid(3289L, "Q384");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRetrieveItem() {
|
public void testRetrieveItem() {
|
||||||
assertEquals("Q345", library.getQid(1234L));
|
assertEquals("Q345", library.getQid(1234L));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateReconciledCells() {
|
public void testUpdateReconciledCells() {
|
||||||
Project project = createCSVProject(TestingData.inceptionWithNewCsv);
|
Project project = createCSVProject(TestingData.inceptionWithNewCsv);
|
||||||
@ -45,18 +69,18 @@ public class NewItemLibraryTest extends RefineTest {
|
|||||||
isMatchedTo("Q865528", project.rows.get(1).cells.get(0));
|
isMatchedTo("Q865528", project.rows.get(1).cells.get(0));
|
||||||
isNewTo(1234L, project.rows.get(2).cells.get(0));
|
isNewTo(1234L, project.rows.get(2).cells.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerialize() {
|
public void testSerialize() {
|
||||||
JacksonSerializationTest.canonicalSerialization(NewItemLibrary.class, library,
|
JacksonSerializationTest.canonicalSerialization(NewItemLibrary.class, library,
|
||||||
"{\"qidMap\":{\"1234\":\"Q345\",\"3289\":\"Q384\"}}");
|
"{\"qidMap\":{\"1234\":\"Q345\",\"3289\":\"Q384\"}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void isMatchedTo(String qid, Cell cell) {
|
private void isMatchedTo(String qid, Cell cell) {
|
||||||
assertEquals(Recon.Judgment.Matched, cell.recon.judgment);
|
assertEquals(Recon.Judgment.Matched, cell.recon.judgment);
|
||||||
assertEquals(qid, cell.recon.match.id);
|
assertEquals(qid, cell.recon.match.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void isNewTo(long id, Cell cell) {
|
private void isNewTo(long id, Cell cell) {
|
||||||
assertEquals(Recon.Judgment.New, cell.recon.judgment);
|
assertEquals(Recon.Judgment.New, cell.recon.judgment);
|
||||||
assertEquals(id, cell.recon.judgmentHistoryEntry);
|
assertEquals(id, cell.recon.judgmentHistoryEntry);
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.editing;
|
package org.openrefine.wikidata.editing;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -11,39 +34,39 @@ import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
||||||
|
|
||||||
public class ReconEntityRewriterTest {
|
public class ReconEntityRewriterTest {
|
||||||
|
|
||||||
NewItemLibrary library = null;
|
NewItemLibrary library = null;
|
||||||
ReconEntityRewriter rewriter = null;
|
ReconEntityRewriter rewriter = null;
|
||||||
ItemIdValue subject = TestingData.newIdA;
|
ItemIdValue subject = TestingData.newIdA;
|
||||||
ItemIdValue newlyCreated = Datamodel.makeWikidataItemIdValue("Q1234");
|
ItemIdValue newlyCreated = Datamodel.makeWikidataItemIdValue("Q1234");
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
library = new NewItemLibrary();
|
library = new NewItemLibrary();
|
||||||
rewriter = new ReconEntityRewriter(library, subject);
|
rewriter = new ReconEntityRewriter(library, subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expectedExceptions=IllegalArgumentException.class)
|
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||||
public void testNotCreatedYet() {
|
public void testNotCreatedYet() {
|
||||||
rewriter.copy(TestingData.newIdB);
|
rewriter.copy(TestingData.newIdB);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccessfulRewrite() {
|
public void testSuccessfulRewrite() {
|
||||||
library.setQid(4567L, "Q1234");
|
library.setQid(4567L, "Q1234");
|
||||||
assertEquals(newlyCreated, rewriter.copy(TestingData.newIdB));
|
assertEquals(newlyCreated, rewriter.copy(TestingData.newIdB));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSubjectNotRewriten() {
|
public void testSubjectNotRewriten() {
|
||||||
assertEquals(subject, rewriter.copy(subject));
|
assertEquals(subject, rewriter.copy(subject));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMatched() {
|
public void testMatched() {
|
||||||
assertEquals(TestingData.matchedId, rewriter.copy(TestingData.matchedId));
|
assertEquals(TestingData.matchedId, rewriter.copy(TestingData.matchedId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRewriteUpdate() {
|
public void testRewriteUpdate() {
|
||||||
library.setQid(4567L, "Q1234");
|
library.setQid(4567L, "Q1234");
|
||||||
@ -52,16 +75,14 @@ public class ReconEntityRewriterTest {
|
|||||||
.deleteStatement(TestingData.generateStatement(subject, TestingData.existingId))
|
.deleteStatement(TestingData.generateStatement(subject, TestingData.existingId))
|
||||||
.addLabel(Datamodel.makeMonolingualTextValue("label", "de"))
|
.addLabel(Datamodel.makeMonolingualTextValue("label", "de"))
|
||||||
.addDescription(Datamodel.makeMonolingualTextValue("beschreibung", "de"))
|
.addDescription(Datamodel.makeMonolingualTextValue("beschreibung", "de"))
|
||||||
.addAlias(Datamodel.makeMonolingualTextValue("darstellung", "de"))
|
.addAlias(Datamodel.makeMonolingualTextValue("darstellung", "de")).build();
|
||||||
.build();
|
|
||||||
ItemUpdate rewritten = rewriter.rewrite(update);
|
ItemUpdate rewritten = rewriter.rewrite(update);
|
||||||
ItemUpdate expected = new ItemUpdateBuilder(subject)
|
ItemUpdate expected = new ItemUpdateBuilder(subject)
|
||||||
.addStatement(TestingData.generateStatement(subject, newlyCreated))
|
.addStatement(TestingData.generateStatement(subject, newlyCreated))
|
||||||
.deleteStatement(TestingData.generateStatement(subject, TestingData.existingId))
|
.deleteStatement(TestingData.generateStatement(subject, TestingData.existingId))
|
||||||
.addLabel(Datamodel.makeMonolingualTextValue("label", "de"))
|
.addLabel(Datamodel.makeMonolingualTextValue("label", "de"))
|
||||||
.addDescription(Datamodel.makeMonolingualTextValue("beschreibung", "de"))
|
.addDescription(Datamodel.makeMonolingualTextValue("beschreibung", "de"))
|
||||||
.addAlias(Datamodel.makeMonolingualTextValue("darstellung", "de"))
|
.addAlias(Datamodel.makeMonolingualTextValue("darstellung", "de")).build();
|
||||||
.build();
|
|
||||||
assertEquals(expected, rewritten);
|
assertEquals(expected, rewritten);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,29 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.exporters;
|
package org.openrefine.wikidata.exporters;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
@ -14,100 +36,101 @@ import org.wikidata.wdtk.datamodel.interfaces.TimeValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
import org.wikidata.wdtk.datamodel.interfaces.Value;
|
||||||
|
|
||||||
public class QSValuePrinterTest {
|
public class QSValuePrinterTest {
|
||||||
|
|
||||||
private QSValuePrinter printer;
|
private QSValuePrinter printer;
|
||||||
|
|
||||||
public QSValuePrinterTest() {
|
public QSValuePrinterTest() {
|
||||||
printer = new QSValuePrinter();
|
printer = new QSValuePrinter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertPrints(String expectedFormat, Value datavalue) {
|
void assertPrints(String expectedFormat, Value datavalue) {
|
||||||
assertEquals(expectedFormat, datavalue.accept(printer));
|
assertEquals(expectedFormat, datavalue.accept(printer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entity id values
|
// Entity id values
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printItemId() {
|
public void printItemId() {
|
||||||
assertPrints("Q42", Datamodel.makeWikidataItemIdValue("Q42"));
|
assertPrints("Q42", Datamodel.makeWikidataItemIdValue("Q42"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printPropertyId() {
|
public void printPropertyId() {
|
||||||
assertPrints("P42", Datamodel.makeWikidataPropertyIdValue("P42"));
|
assertPrints("P42", Datamodel.makeWikidataPropertyIdValue("P42"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printNewItemId() {
|
public void printNewItemId() {
|
||||||
ReconEntityIdValue id = TestingData.makeNewItemIdValue(12345L, "my new item");
|
ReconEntityIdValue id = TestingData.makeNewItemIdValue(12345L, "my new item");
|
||||||
assertEquals("LAST", id.accept(printer));
|
assertEquals("LAST", id.accept(printer));
|
||||||
// because no entity was previously created
|
// because no entity was previously created
|
||||||
|
|
||||||
ReconEntityIdValue differentId = TestingData.makeMatchedItemIdValue("Q78", "my existing item");
|
ReconEntityIdValue differentId = TestingData.makeMatchedItemIdValue("Q78", "my existing item");
|
||||||
assertEquals("Q78", differentId.accept(printer));
|
assertEquals("Q78", differentId.accept(printer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Globe coordinates
|
// Globe coordinates
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printGlobeCoordinate() {
|
public void printGlobeCoordinate() {
|
||||||
// I don't see how to avoid the trailing zeros - in any case it's not a big deal because
|
// I don't see how to avoid the trailing zeros - in any case it's not a big deal
|
||||||
// the precision is governed by a different parameter that QuickStatements does not support.
|
// because
|
||||||
|
// the precision is governed by a different parameter that QuickStatements does
|
||||||
|
// not support.
|
||||||
assertPrints("@43.261930/10.927080", Datamodel.makeGlobeCoordinatesValue(43.26193, 10.92708,
|
assertPrints("@43.261930/10.927080", Datamodel.makeGlobeCoordinatesValue(43.26193, 10.92708,
|
||||||
GlobeCoordinatesValue.PREC_DEGREE, GlobeCoordinatesValue.GLOBE_EARTH));
|
GlobeCoordinatesValue.PREC_DEGREE, GlobeCoordinatesValue.GLOBE_EARTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Monolingual text values
|
// Monolingual text values
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printMonolingualTextValue() {
|
public void printMonolingualTextValue() {
|
||||||
assertPrints("pl:\"Krzyżacy\"", Datamodel.makeMonolingualTextValue("Krzyżacy", "pl"));
|
assertPrints("pl:\"Krzyżacy\"", Datamodel.makeMonolingualTextValue("Krzyżacy", "pl"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quantity values
|
// Quantity values
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printSimpleQuantityValue() {
|
public void printSimpleQuantityValue() {
|
||||||
assertPrints("10.00", Datamodel.makeQuantityValue(new BigDecimal("10.00"),
|
assertPrints("10.00", Datamodel.makeQuantityValue(new BigDecimal("10.00"), null, null, "1"));
|
||||||
null, null, "1"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printQuantityValueWithUnit() {
|
public void printQuantityValueWithUnit() {
|
||||||
assertPrints("10.00U11573", Datamodel.makeQuantityValue(new BigDecimal("10.00"),
|
assertPrints("10.00U11573", Datamodel.makeQuantityValue(new BigDecimal("10.00"), null, null,
|
||||||
null, null, "http://www.wikidata.org/entity/Q11573"));
|
"http://www.wikidata.org/entity/Q11573"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printQuantityValueWithBounds() {
|
public void printQuantityValueWithBounds() {
|
||||||
assertPrints("10.00[9.0,11.05]", Datamodel.makeQuantityValue(new BigDecimal("10.00"),
|
assertPrints("10.00[9.0,11.05]", Datamodel.makeQuantityValue(new BigDecimal("10.00"), new BigDecimal("9.0"),
|
||||||
new BigDecimal("9.0"), new BigDecimal("11.05"), "1"));
|
new BigDecimal("11.05"), "1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printFullQuantity() {
|
public void printFullQuantity() {
|
||||||
assertPrints("10.00[9.0,11.05]U11573", Datamodel.makeQuantityValue(new BigDecimal("10.00"),
|
assertPrints("10.00[9.0,11.05]U11573", Datamodel.makeQuantityValue(new BigDecimal("10.00"),
|
||||||
new BigDecimal("9.0"), new BigDecimal("11.05"), "http://www.wikidata.org/entity/Q11573"));
|
new BigDecimal("9.0"), new BigDecimal("11.05"), "http://www.wikidata.org/entity/Q11573"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// String values
|
// String values
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printString() {
|
public void printString() {
|
||||||
assertPrints("\"hello\"", Datamodel.makeStringValue("hello"));
|
assertPrints("\"hello\"", Datamodel.makeStringValue("hello"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time values
|
// Time values
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printYear() {
|
public void printYear() {
|
||||||
assertPrints("+1586-00-00T00:00:00Z/9", Datamodel.makeTimeValue(1586L, (byte)0, (byte)0, (byte)0,
|
assertPrints("+1586-00-00T00:00:00Z/9", Datamodel.makeTimeValue(1586L, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
|
||||||
(byte)0, (byte)0, (byte)9, 0, 0, 0, TimeValue.CM_GREGORIAN_PRO));
|
(byte) 0, (byte) 9, 0, 0, 0, TimeValue.CM_GREGORIAN_PRO));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printDay() {
|
public void printDay() {
|
||||||
assertPrints("+1586-03-09T00:00:00Z/11", Datamodel.makeTimeValue(1586L, (byte)3, (byte)9, (byte)0,
|
assertPrints("+1586-03-09T00:00:00Z/11", Datamodel.makeTimeValue(1586L, (byte) 3, (byte) 9, (byte) 0, (byte) 0,
|
||||||
(byte)0, (byte)0, (byte)11, 0, 0, 0, TimeValue.CM_GREGORIAN_PRO));
|
(byte) 0, (byte) 11, 0, 0, 0, TimeValue.CM_GREGORIAN_PRO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.exporters;
|
package org.openrefine.wikidata.exporters;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -14,7 +37,6 @@ import org.openrefine.wikidata.schema.WikibaseSchema;
|
|||||||
import org.openrefine.wikidata.testing.TestingData;
|
import org.openrefine.wikidata.testing.TestingData;
|
||||||
import org.openrefine.wikidata.updates.ItemUpdate;
|
import org.openrefine.wikidata.updates.ItemUpdate;
|
||||||
import org.openrefine.wikidata.updates.ItemUpdateBuilder;
|
import org.openrefine.wikidata.updates.ItemUpdateBuilder;
|
||||||
import org.openrefine.wikidata.updates.scheduler.UpdateSchedulerTest;
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.Claim;
|
import org.wikidata.wdtk.datamodel.interfaces.Claim;
|
||||||
@ -30,95 +52,93 @@ import com.google.refine.tests.RefineTest;
|
|||||||
|
|
||||||
public class QuickStatementsExporterTest extends RefineTest {
|
public class QuickStatementsExporterTest extends RefineTest {
|
||||||
|
|
||||||
private QuickStatementsExporter exporter = new QuickStatementsExporter();
|
private QuickStatementsExporter exporter = new QuickStatementsExporter();
|
||||||
private ItemIdValue newIdA = TestingData.makeNewItemIdValue(1234L, "new item A");
|
private ItemIdValue newIdA = TestingData.makeNewItemIdValue(1234L, "new item A");
|
||||||
private ItemIdValue newIdB = TestingData.makeNewItemIdValue(5678L, "new item B");
|
private ItemIdValue newIdB = TestingData.makeNewItemIdValue(5678L, "new item B");
|
||||||
private ItemIdValue qid1 = Datamodel.makeWikidataItemIdValue("Q1377");
|
private ItemIdValue qid1 = Datamodel.makeWikidataItemIdValue("Q1377");
|
||||||
private ItemIdValue qid2 = Datamodel.makeWikidataItemIdValue("Q865528");
|
private ItemIdValue qid2 = Datamodel.makeWikidataItemIdValue("Q865528");
|
||||||
|
|
||||||
private String export(ItemUpdate... itemUpdates) throws IOException {
|
private String export(ItemUpdate... itemUpdates)
|
||||||
StringWriter writer = new StringWriter();
|
throws IOException {
|
||||||
exporter.translateItemList(Arrays.asList(itemUpdates), writer);
|
StringWriter writer = new StringWriter();
|
||||||
return writer.toString();
|
exporter.translateItemList(Arrays.asList(itemUpdates), writer);
|
||||||
}
|
return writer.toString();
|
||||||
|
}
|
||||||
@Test
|
|
||||||
public void testSimpleProject() throws JSONException, IOException {
|
@Test
|
||||||
Project project = this.createCSVProject(
|
public void testSimpleProject()
|
||||||
TestingData.inceptionWithNewCsv);
|
throws JSONException, IOException {
|
||||||
TestingData.reconcileInceptionCells(project);
|
Project project = this.createCSVProject(TestingData.inceptionWithNewCsv);
|
||||||
JSONObject serialized = TestingData.jsonFromFile("data/schema/inception.json");
|
TestingData.reconcileInceptionCells(project);
|
||||||
WikibaseSchema schema = WikibaseSchema.reconstruct(serialized);
|
JSONObject serialized = TestingData.jsonFromFile("data/schema/inception.json");
|
||||||
project.overlayModels.put("wikibaseSchema", schema);
|
WikibaseSchema schema = WikibaseSchema.reconstruct(serialized);
|
||||||
Engine engine = new Engine(project);
|
project.overlayModels.put("wikibaseSchema", schema);
|
||||||
|
Engine engine = new Engine(project);
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
Properties properties = new Properties();
|
StringWriter writer = new StringWriter();
|
||||||
exporter.export(project, properties, engine, writer);
|
Properties properties = new Properties();
|
||||||
assertEquals(TestingData.inceptionWithNewQS, writer.toString());
|
exporter.export(project, properties, engine, writer);
|
||||||
}
|
assertEquals(TestingData.inceptionWithNewQS, writer.toString());
|
||||||
|
}
|
||||||
@Test
|
|
||||||
public void testImpossibleScheduling() throws IOException {
|
@Test
|
||||||
Statement sNewAtoNewB = TestingData.generateStatement(newIdA, newIdB);
|
public void testImpossibleScheduling()
|
||||||
ItemUpdate update = new ItemUpdateBuilder(newIdA).addStatement(sNewAtoNewB).build();
|
throws IOException {
|
||||||
|
Statement sNewAtoNewB = TestingData.generateStatement(newIdA, newIdB);
|
||||||
assertEquals(QuickStatementsExporter.impossibleSchedulingErrorMessage,
|
ItemUpdate update = new ItemUpdateBuilder(newIdA).addStatement(sNewAtoNewB).build();
|
||||||
export(update));
|
|
||||||
}
|
assertEquals(QuickStatementsExporter.impossibleSchedulingErrorMessage, export(update));
|
||||||
|
}
|
||||||
@Test
|
|
||||||
public void testNameDesc() throws IOException {
|
@Test
|
||||||
ItemUpdate update = new ItemUpdateBuilder(newIdA)
|
public void testNameDesc()
|
||||||
.addLabel(Datamodel.makeMonolingualTextValue("my new item", "en"))
|
throws IOException {
|
||||||
.addDescription(Datamodel.makeMonolingualTextValue("isn't it awesome?", "en"))
|
ItemUpdate update = new ItemUpdateBuilder(newIdA)
|
||||||
.addAlias(Datamodel.makeMonolingualTextValue("fabitem", "en"))
|
.addLabel(Datamodel.makeMonolingualTextValue("my new item", "en"))
|
||||||
.build();
|
.addDescription(Datamodel.makeMonolingualTextValue("isn't it awesome?", "en"))
|
||||||
|
.addAlias(Datamodel.makeMonolingualTextValue("fabitem", "en")).build();
|
||||||
assertEquals("CREATE\n"+
|
|
||||||
"LAST\tLen\t\"my new item\"\n"+
|
assertEquals("CREATE\n" + "LAST\tLen\t\"my new item\"\n" + "LAST\tDen\t\"isn't it awesome?\"\n"
|
||||||
"LAST\tDen\t\"isn't it awesome?\"\n"+
|
+ "LAST\tAen\t\"fabitem\"\n", export(update));
|
||||||
"LAST\tAen\t\"fabitem\"\n",
|
}
|
||||||
export(update));
|
|
||||||
}
|
@Test
|
||||||
|
public void testDeleteStatement()
|
||||||
@Test
|
throws IOException {
|
||||||
public void testDeleteStatement() throws IOException {
|
ItemUpdate update = new ItemUpdateBuilder(qid1).deleteStatement(TestingData.generateStatement(qid1, qid2))
|
||||||
ItemUpdate update = new ItemUpdateBuilder(qid1)
|
.build();
|
||||||
.deleteStatement(TestingData.generateStatement(qid1, qid2))
|
|
||||||
.build();
|
assertEquals("- Q1377\tP38\tQ865528\n", export(update));
|
||||||
|
}
|
||||||
assertEquals("- Q1377\tP38\tQ865528\n", export(update));
|
|
||||||
}
|
@Test
|
||||||
|
public void testQualifier()
|
||||||
@Test
|
throws IOException {
|
||||||
public void testQualifier() throws IOException {
|
Statement baseStatement = TestingData.generateStatement(qid1, qid2);
|
||||||
Statement baseStatement = TestingData.generateStatement(qid1, qid2);
|
Statement otherStatement = TestingData.generateStatement(qid2, qid1);
|
||||||
Statement otherStatement = TestingData.generateStatement(qid2, qid1);
|
Snak qualifierSnak = otherStatement.getClaim().getMainSnak();
|
||||||
Snak qualifierSnak = otherStatement.getClaim().getMainSnak();
|
SnakGroup group = Datamodel.makeSnakGroup(Collections.singletonList(qualifierSnak));
|
||||||
SnakGroup group = Datamodel.makeSnakGroup(Collections.singletonList(qualifierSnak));
|
Claim claim = Datamodel.makeClaim(qid1, baseStatement.getClaim().getMainSnak(),
|
||||||
Claim claim = Datamodel.makeClaim(qid1, baseStatement.getClaim().getMainSnak(),
|
Collections.singletonList(group));
|
||||||
Collections.singletonList(group));
|
Statement statement = Datamodel.makeStatement(claim, Collections.emptyList(), StatementRank.NORMAL, "");
|
||||||
Statement statement = Datamodel.makeStatement(claim, Collections.emptyList(), StatementRank.NORMAL, "");
|
ItemUpdate update = new ItemUpdateBuilder(qid1).addStatement(statement).build();
|
||||||
ItemUpdate update = new ItemUpdateBuilder(qid1)
|
|
||||||
.addStatement(statement)
|
assertEquals("Q1377\tP38\tQ865528\tP38\tQ1377\n", export(update));
|
||||||
.build();
|
}
|
||||||
|
|
||||||
assertEquals("Q1377\tP38\tQ865528\tP38\tQ1377\n", export(update));
|
@Test
|
||||||
}
|
public void testNoSchema()
|
||||||
|
throws IOException {
|
||||||
@Test
|
Project project = this.createCSVProject("a,b\nc,d");
|
||||||
public void testNoSchema() throws IOException {
|
Engine engine = new Engine(project);
|
||||||
Project project = this.createCSVProject("a,b\nc,d");
|
StringWriter writer = new StringWriter();
|
||||||
Engine engine = new Engine(project);
|
Properties properties = new Properties();
|
||||||
StringWriter writer = new StringWriter();
|
exporter.export(project, properties, engine, writer);
|
||||||
Properties properties = new Properties();
|
assertEquals(QuickStatementsExporter.noSchemaErrorMessage, writer.toString());
|
||||||
exporter.export(project, properties, engine, writer);
|
}
|
||||||
assertEquals(QuickStatementsExporter.noSchemaErrorMessage, writer.toString());
|
|
||||||
}
|
@Test
|
||||||
|
public void testGetContentType() {
|
||||||
@Test
|
assertEquals("text/plain", exporter.getContentType());
|
||||||
public void testGetContentType() {
|
}
|
||||||
assertEquals("text/plain", exporter.getContentType());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,31 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.operations;
|
package org.openrefine.wikidata.operations;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.LineNumberReader;
|
import java.io.LineNumberReader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
@ -12,9 +38,6 @@ import org.openrefine.wikidata.testing.JacksonSerializationTest;
|
|||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import com.google.refine.history.Change;
|
import com.google.refine.history.Change;
|
||||||
import com.google.refine.model.AbstractOperation;
|
import com.google.refine.model.AbstractOperation;
|
||||||
import com.google.refine.model.Project;
|
import com.google.refine.model.Project;
|
||||||
@ -25,11 +48,11 @@ import com.google.refine.util.Pool;
|
|||||||
import edu.mit.simile.butterfly.ButterflyModule;
|
import edu.mit.simile.butterfly.ButterflyModule;
|
||||||
|
|
||||||
public abstract class OperationTest extends RefineTest {
|
public abstract class OperationTest extends RefineTest {
|
||||||
|
|
||||||
protected Project project = null;
|
protected Project project = null;
|
||||||
protected ButterflyModule module = null;
|
protected ButterflyModule module = null;
|
||||||
protected Pool pool = null;
|
protected Pool pool = null;
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
project = createCSVProject("a,b\nc,d");
|
project = createCSVProject("a,b\nc,d");
|
||||||
@ -37,17 +60,20 @@ public abstract class OperationTest extends RefineTest {
|
|||||||
when(module.getName()).thenReturn("wikidata");
|
when(module.getName()).thenReturn("wikidata");
|
||||||
pool = new Pool();
|
pool = new Pool();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void registerOperation(String name, Class klass) {
|
protected void registerOperation(String name, Class klass) {
|
||||||
OperationRegistry.registerOperation(module, name, klass);
|
OperationRegistry.registerOperation(module, name, klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract AbstractOperation reconstruct() throws Exception;
|
public abstract AbstractOperation reconstruct()
|
||||||
|
throws Exception;
|
||||||
public abstract JSONObject getJson() throws Exception;
|
|
||||||
|
public abstract JSONObject getJson()
|
||||||
|
throws Exception;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReconstruct() throws Exception {
|
public void testReconstruct()
|
||||||
|
throws Exception {
|
||||||
JSONObject json = getJson();
|
JSONObject json = getJson();
|
||||||
AbstractOperation op = reconstruct();
|
AbstractOperation op = reconstruct();
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
@ -55,13 +81,14 @@ public abstract class OperationTest extends RefineTest {
|
|||||||
op.write(jsonWriter, new Properties());
|
op.write(jsonWriter, new Properties());
|
||||||
JacksonSerializationTest.assertJsonEquals(json.toString(), writer.toString());
|
JacksonSerializationTest.assertJsonEquals(json.toString(), writer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LineNumberReader makeReader(String input) {
|
protected LineNumberReader makeReader(String input) {
|
||||||
StringReader reader = new StringReader(input);
|
StringReader reader = new StringReader(input);
|
||||||
return new LineNumberReader(reader);
|
return new LineNumberReader(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String saveChange(Change change) throws IOException {
|
protected String saveChange(Change change)
|
||||||
|
throws IOException {
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
change.save(writer, new Properties());
|
change.save(writer, new Properties());
|
||||||
return writer.toString();
|
return writer.toString();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.operations;
|
package org.openrefine.wikidata.operations;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -14,41 +37,43 @@ import com.google.refine.model.AbstractOperation;
|
|||||||
import com.google.refine.model.Recon;
|
import com.google.refine.model.Recon;
|
||||||
|
|
||||||
public class PerformWikibaseEditsOperationTest extends OperationTest {
|
public class PerformWikibaseEditsOperationTest extends OperationTest {
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void registerOperation() {
|
public void registerOperation() {
|
||||||
registerOperation("perform-wikibase-edits", PerformWikibaseEditsOperation.class);
|
registerOperation("perform-wikibase-edits", PerformWikibaseEditsOperation.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractOperation reconstruct() throws Exception {
|
public AbstractOperation reconstruct()
|
||||||
|
throws Exception {
|
||||||
JSONObject json = getJson();
|
JSONObject json = getJson();
|
||||||
return PerformWikibaseEditsOperation.reconstruct(project, json);
|
return PerformWikibaseEditsOperation.reconstruct(project, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject getJson() throws Exception {
|
public JSONObject getJson()
|
||||||
|
throws Exception {
|
||||||
return TestingData.jsonFromFile("data/operations/perform-edits.json");
|
return TestingData.jsonFromFile("data/operations/perform-edits.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoadChange() throws Exception {
|
public void testLoadChange()
|
||||||
String changeString = "newItems={\"qidMap\":{\"1234\":\"Q789\"}}\n" +
|
throws Exception {
|
||||||
"/ec/\n";
|
String changeString = "newItems={\"qidMap\":{\"1234\":\"Q789\"}}\n" + "/ec/\n";
|
||||||
LineNumberReader reader = makeReader(changeString);
|
LineNumberReader reader = makeReader(changeString);
|
||||||
Change change = PerformWikibaseEditsOperation.PerformWikibaseEditsChange.load(reader, pool);
|
Change change = PerformWikibaseEditsOperation.PerformWikibaseEditsChange.load(reader, pool);
|
||||||
|
|
||||||
project.rows.get(0).cells.set(0, TestingData.makeNewItemCell(1234L, "my new item"));
|
project.rows.get(0).cells.set(0, TestingData.makeNewItemCell(1234L, "my new item"));
|
||||||
|
|
||||||
change.apply(project);
|
change.apply(project);
|
||||||
|
|
||||||
assertEquals(Recon.Judgment.Matched, project.rows.get(0).cells.get(0).recon.judgment);
|
assertEquals(Recon.Judgment.Matched, project.rows.get(0).cells.get(0).recon.judgment);
|
||||||
assertEquals("Q789", project.rows.get(0).cells.get(0).recon.match.id);
|
assertEquals("Q789", project.rows.get(0).cells.get(0).recon.match.id);
|
||||||
|
|
||||||
change.revert(project);
|
change.revert(project);
|
||||||
|
|
||||||
assertEquals(Recon.Judgment.New, project.rows.get(0).cells.get(0).recon.judgment);
|
assertEquals(Recon.Judgment.New, project.rows.get(0).cells.get(0).recon.judgment);
|
||||||
|
|
||||||
assertEquals(changeString, saveChange(change));
|
assertEquals(changeString, saveChange(change));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.operations;
|
package org.openrefine.wikidata.operations;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -14,44 +37,44 @@ import org.testng.annotations.Test;
|
|||||||
import com.google.refine.history.Change;
|
import com.google.refine.history.Change;
|
||||||
import com.google.refine.model.AbstractOperation;
|
import com.google.refine.model.AbstractOperation;
|
||||||
|
|
||||||
|
|
||||||
public class SaveWikibaseSchemaOperationTest extends OperationTest {
|
public class SaveWikibaseSchemaOperationTest extends OperationTest {
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void registerOperation() {
|
public void registerOperation() {
|
||||||
registerOperation("save-wikibase-schema", SaveWikibaseSchemaOperation.class);
|
registerOperation("save-wikibase-schema", SaveWikibaseSchemaOperation.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractOperation reconstruct() throws Exception {
|
public AbstractOperation reconstruct()
|
||||||
|
throws Exception {
|
||||||
return SaveWikibaseSchemaOperation.reconstruct(project, getJson());
|
return SaveWikibaseSchemaOperation.reconstruct(project, getJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject getJson() throws Exception {
|
public JSONObject getJson()
|
||||||
|
throws Exception {
|
||||||
return TestingData.jsonFromFile("data/operations/save-schema.json");
|
return TestingData.jsonFromFile("data/operations/save-schema.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLoadChange() throws Exception {
|
public void testLoadChange()
|
||||||
|
throws Exception {
|
||||||
JSONObject schemaJson = TestingData.jsonFromFile("data/schema/inception.json");
|
JSONObject schemaJson = TestingData.jsonFromFile("data/schema/inception.json");
|
||||||
String changeString =
|
String changeString = "newSchema=" + schemaJson.toString() + "\n" + "oldSchema=\n" + "/ec/";
|
||||||
"newSchema="+schemaJson.toString()+"\n" +
|
|
||||||
"oldSchema=\n" +
|
|
||||||
"/ec/";
|
|
||||||
WikibaseSchema schema = WikibaseSchema.reconstruct(schemaJson);
|
WikibaseSchema schema = WikibaseSchema.reconstruct(schemaJson);
|
||||||
|
|
||||||
LineNumberReader reader = makeReader(changeString);
|
LineNumberReader reader = makeReader(changeString);
|
||||||
Change change = SaveWikibaseSchemaOperation.WikibaseSchemaChange.load(reader, pool);
|
Change change = SaveWikibaseSchemaOperation.WikibaseSchemaChange.load(reader, pool);
|
||||||
|
|
||||||
change.apply(project);
|
change.apply(project);
|
||||||
|
|
||||||
assertEquals(schema, project.overlayModels.get(SaveWikibaseSchemaOperation.WikibaseSchemaChange.overlayModelKey));
|
assertEquals(schema,
|
||||||
|
project.overlayModels.get(SaveWikibaseSchemaOperation.WikibaseSchemaChange.overlayModelKey));
|
||||||
|
|
||||||
change.revert(project);
|
change.revert(project);
|
||||||
|
|
||||||
assertNull(project.overlayModels.get(SaveWikibaseSchemaOperation.WikibaseSchemaChange.overlayModelKey));
|
assertNull(project.overlayModels.get(SaveWikibaseSchemaOperation.WikibaseSchemaChange.overlayModelKey));
|
||||||
|
|
||||||
saveChange(change); // not checking for equality because JSON serialization varies
|
saveChange(change); // not checking for equality because JSON serialization varies
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -8,14 +31,13 @@ import java.util.stream.Collectors;
|
|||||||
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
||||||
|
|
||||||
|
|
||||||
public class MockConstraintFetcher implements ConstraintFetcher {
|
public class MockConstraintFetcher implements ConstraintFetcher {
|
||||||
|
|
||||||
public static PropertyIdValue pidWithInverse = Datamodel.makeWikidataPropertyIdValue("P350");
|
public static PropertyIdValue pidWithInverse = Datamodel.makeWikidataPropertyIdValue("P350");
|
||||||
public static PropertyIdValue inversePid = Datamodel.makeWikidataPropertyIdValue("P57");
|
public static PropertyIdValue inversePid = Datamodel.makeWikidataPropertyIdValue("P57");
|
||||||
public static PropertyIdValue allowedQualifierPid = Datamodel.makeWikidataPropertyIdValue("P34");
|
public static PropertyIdValue allowedQualifierPid = Datamodel.makeWikidataPropertyIdValue("P34");
|
||||||
public static PropertyIdValue mandatoryQualifierPid = Datamodel.makeWikidataPropertyIdValue("P97");
|
public static PropertyIdValue mandatoryQualifierPid = Datamodel.makeWikidataPropertyIdValue("P97");
|
||||||
|
|
||||||
public static PropertyIdValue mainSnakPid = Datamodel.makeWikidataPropertyIdValue("P1234");
|
public static PropertyIdValue mainSnakPid = Datamodel.makeWikidataPropertyIdValue("P1234");
|
||||||
public static PropertyIdValue qualifierPid = Datamodel.makeWikidataPropertyIdValue("P987");
|
public static PropertyIdValue qualifierPid = Datamodel.makeWikidataPropertyIdValue("P987");
|
||||||
public static PropertyIdValue referencePid = Datamodel.makeWikidataPropertyIdValue("P384");
|
public static PropertyIdValue referencePid = Datamodel.makeWikidataPropertyIdValue("P384");
|
||||||
@ -26,8 +48,8 @@ public class MockConstraintFetcher implements ConstraintFetcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constraint is purposely left inconsistent (the inverse
|
* This constraint is purposely left inconsistent (the inverse constraint holds
|
||||||
* constraint holds only on one side).
|
* only on one side).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public PropertyIdValue getInversePid(PropertyIdValue pid) {
|
public PropertyIdValue getInversePid(PropertyIdValue pid) {
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -9,13 +32,13 @@ import org.testng.annotations.Test;
|
|||||||
public class QAWarningStoreTest {
|
public class QAWarningStoreTest {
|
||||||
|
|
||||||
public static String exampleJson = "{\"max_severity\":\"CRITICAL\",\"nb_warnings\":5,"
|
public static String exampleJson = "{\"max_severity\":\"CRITICAL\",\"nb_warnings\":5,"
|
||||||
+"\"warnings\":[{\"type\":\"new-item-without-label\",\"bucketId\":null,"
|
+ "\"warnings\":[{\"type\":\"new-item-without-label\",\"bucketId\":null,"
|
||||||
+"\"severity\":\"CRITICAL\",\"count\":3},{\"type\":\"add-statements-with-invalid-format\","
|
+ "\"severity\":\"CRITICAL\",\"count\":3},{\"type\":\"add-statements-with-invalid-format\","
|
||||||
+"\"bucketId\":\"P2427\",\"severity\":\"IMPORTANT\",\"count\":2}]}";
|
+ "\"bucketId\":\"P2427\",\"severity\":\"IMPORTANT\",\"count\":2}]}";
|
||||||
|
|
||||||
private QAWarningStore store;
|
private QAWarningStore store;
|
||||||
private QAWarning otherWarning;
|
private QAWarning otherWarning;
|
||||||
|
|
||||||
@BeforeMethod
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
store = new QAWarningStore();
|
store = new QAWarningStore();
|
||||||
@ -24,18 +47,18 @@ public class QAWarningStoreTest {
|
|||||||
otherWarning = new QAWarning("new-item-without-label", null, QAWarning.Severity.CRITICAL, 3);
|
otherWarning = new QAWarning("new-item-without-label", null, QAWarning.Severity.CRITICAL, 3);
|
||||||
store.addWarning(otherWarning);
|
store.addWarning(otherWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerialize() {
|
public void testSerialize() {
|
||||||
JacksonSerializationTest.testSerialize(store, exampleJson);
|
JacksonSerializationTest.testSerialize(store, exampleJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCount() {
|
public void testCount() {
|
||||||
assertEquals(5, store.getNbWarnings());
|
assertEquals(5, store.getNbWarnings());
|
||||||
assertEquals(2, store.getWarnings().size());
|
assertEquals(2, store.getWarnings().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMaxSeverity() {
|
public void testMaxSeverity() {
|
||||||
assertEquals(QAWarning.Severity.CRITICAL, store.getMaxSeverity());
|
assertEquals(QAWarning.Severity.CRITICAL, store.getMaxSeverity());
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -6,25 +29,20 @@ import org.openrefine.wikidata.testing.JacksonSerializationTest;
|
|||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
public class QAWarningTest {
|
public class QAWarningTest {
|
||||||
|
|
||||||
public static QAWarning exampleWarning = new QAWarning("add-statements-with-invalid-format",
|
public static QAWarning exampleWarning = new QAWarning("add-statements-with-invalid-format", "P2427",
|
||||||
"P2427",
|
QAWarning.Severity.IMPORTANT, 1);
|
||||||
QAWarning.Severity.IMPORTANT,
|
public static String exampleJson = "{\"severity\":\"IMPORTANT\","
|
||||||
1);
|
+ "\"count\":1,\"bucketId\":\"P2427\",\"type\":\"add-statements-with-invalid-format\"}";
|
||||||
public static String exampleJson =
|
|
||||||
"{\"severity\":\"IMPORTANT\","+
|
|
||||||
"\"count\":1,\"bucketId\":\"P2427\",\"type\":\"add-statements-with-invalid-format\"}";
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerialize() {
|
public void testSerialize() {
|
||||||
JacksonSerializationTest.testSerialize(exampleWarning, exampleJson);
|
JacksonSerializationTest.testSerialize(exampleWarning, exampleJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAggregate() {
|
public void testAggregate() {
|
||||||
QAWarning firstWarning = new QAWarning("add-statements-with-invalid-format",
|
QAWarning firstWarning = new QAWarning("add-statements-with-invalid-format", "P2427", QAWarning.Severity.INFO,
|
||||||
"P2427",
|
|
||||||
QAWarning.Severity.INFO,
|
|
||||||
1);
|
1);
|
||||||
firstWarning.setProperty("foo", "bar");
|
firstWarning.setProperty("foo", "bar");
|
||||||
assertEquals(exampleWarning.getAggregationId(), firstWarning.getAggregationId());
|
assertEquals(exampleWarning.getAggregationId(), firstWarning.getAggregationId());
|
||||||
@ -35,13 +53,10 @@ public class QAWarningTest {
|
|||||||
assertEquals(exampleWarning.getSeverity(), merged.getSeverity());
|
assertEquals(exampleWarning.getSeverity(), merged.getSeverity());
|
||||||
assertEquals("bar", merged.getProperties().get("foo"));
|
assertEquals("bar", merged.getProperties().get("foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCompare() {
|
public void testCompare() {
|
||||||
QAWarning otherWarning = new QAWarning("no-reference",
|
QAWarning otherWarning = new QAWarning("no-reference", "no-reference", QAWarning.Severity.WARNING, 1);
|
||||||
"no-reference",
|
|
||||||
QAWarning.Severity.WARNING,
|
|
||||||
1);
|
|
||||||
assertEquals(1, otherWarning.compareTo(exampleWarning));
|
assertEquals(1, otherWarning.compareTo(exampleWarning));
|
||||||
assertEquals(-1, exampleWarning.compareTo(otherWarning));
|
assertEquals(-1, exampleWarning.compareTo(otherWarning));
|
||||||
assertEquals(0, exampleWarning.compareTo(exampleWarning));
|
assertEquals(0, exampleWarning.compareTo(exampleWarning));
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa;
|
package org.openrefine.wikidata.qa;
|
||||||
|
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
@ -8,9 +31,9 @@ import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class WikidataConstraintFetcherTests {
|
public class WikidataConstraintFetcherTests {
|
||||||
|
|
||||||
private ConstraintFetcher fetcher;
|
private ConstraintFetcher fetcher;
|
||||||
|
|
||||||
private PropertyIdValue headOfGovernment;
|
private PropertyIdValue headOfGovernment;
|
||||||
private PropertyIdValue startTime;
|
private PropertyIdValue startTime;
|
||||||
private PropertyIdValue endTime;
|
private PropertyIdValue endTime;
|
||||||
@ -20,7 +43,7 @@ public class WikidataConstraintFetcherTests {
|
|||||||
private PropertyIdValue partOf;
|
private PropertyIdValue partOf;
|
||||||
private PropertyIdValue referenceURL;
|
private PropertyIdValue referenceURL;
|
||||||
private PropertyIdValue reasonForDeprecation;
|
private PropertyIdValue reasonForDeprecation;
|
||||||
|
|
||||||
public WikidataConstraintFetcherTests() {
|
public WikidataConstraintFetcherTests() {
|
||||||
fetcher = new WikidataConstraintFetcher();
|
fetcher = new WikidataConstraintFetcher();
|
||||||
headOfGovernment = Datamodel.makeWikidataPropertyIdValue("P6");
|
headOfGovernment = Datamodel.makeWikidataPropertyIdValue("P6");
|
||||||
@ -33,41 +56,41 @@ public class WikidataConstraintFetcherTests {
|
|||||||
referenceURL = Datamodel.makeWikidataPropertyIdValue("P854");
|
referenceURL = Datamodel.makeWikidataPropertyIdValue("P854");
|
||||||
reasonForDeprecation = Datamodel.makeWikidataPropertyIdValue("P2241");
|
reasonForDeprecation = Datamodel.makeWikidataPropertyIdValue("P2241");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetFormatConstraint() {
|
public void testGetFormatConstraint() {
|
||||||
String regex = fetcher.getFormatRegex(gridId);
|
String regex = fetcher.getFormatRegex(gridId);
|
||||||
Pattern pattern = Pattern.compile(regex);
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
|
||||||
Assert.assertTrue(pattern.matcher("grid.470811.b").matches());
|
Assert.assertTrue(pattern.matcher("grid.470811.b").matches());
|
||||||
Assert.assertFalse(pattern.matcher("501100006367").matches());
|
Assert.assertFalse(pattern.matcher("501100006367").matches());
|
||||||
|
|
||||||
Assert.assertNull(fetcher.getFormatRegex(instanceOf));
|
Assert.assertNull(fetcher.getFormatRegex(instanceOf));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetInverseConstraint() {
|
public void testGetInverseConstraint() {
|
||||||
Assert.assertEquals(fetcher.getInversePid(partOf), hasPart);
|
Assert.assertEquals(fetcher.getInversePid(partOf), hasPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnlyReferences() {
|
public void testOnlyReferences() {
|
||||||
Assert.assertTrue(fetcher.isForReferencesOnly(referenceURL));
|
Assert.assertTrue(fetcher.isForReferencesOnly(referenceURL));
|
||||||
Assert.assertFalse(fetcher.isForReferencesOnly(reasonForDeprecation));
|
Assert.assertFalse(fetcher.isForReferencesOnly(reasonForDeprecation));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnlyQualifiers() {
|
public void testOnlyQualifiers() {
|
||||||
Assert.assertTrue(fetcher.isForQualifiersOnly(reasonForDeprecation));
|
Assert.assertTrue(fetcher.isForQualifiersOnly(reasonForDeprecation));
|
||||||
Assert.assertFalse(fetcher.isForQualifiersOnly(headOfGovernment));
|
Assert.assertFalse(fetcher.isForQualifiersOnly(headOfGovernment));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnlyValues() {
|
public void testOnlyValues() {
|
||||||
Assert.assertTrue(fetcher.isForValuesOnly(headOfGovernment));
|
Assert.assertTrue(fetcher.isForValuesOnly(headOfGovernment));
|
||||||
Assert.assertFalse(fetcher.isForValuesOnly(referenceURL));
|
Assert.assertFalse(fetcher.isForValuesOnly(referenceURL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAllowedQualifiers() {
|
public void testAllowedQualifiers() {
|
||||||
Assert.assertTrue(fetcher.allowedQualifiers(headOfGovernment).contains(startTime));
|
Assert.assertTrue(fetcher.allowedQualifiers(headOfGovernment).contains(startTime));
|
||||||
@ -75,20 +98,20 @@ public class WikidataConstraintFetcherTests {
|
|||||||
Assert.assertFalse(fetcher.allowedQualifiers(headOfGovernment).contains(headOfGovernment));
|
Assert.assertFalse(fetcher.allowedQualifiers(headOfGovernment).contains(headOfGovernment));
|
||||||
Assert.assertNull(fetcher.allowedQualifiers(startTime));
|
Assert.assertNull(fetcher.allowedQualifiers(startTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMandatoryQualifiers() {
|
public void testMandatoryQualifiers() {
|
||||||
Assert.assertTrue(fetcher.mandatoryQualifiers(headOfGovernment).contains(startTime));
|
Assert.assertTrue(fetcher.mandatoryQualifiers(headOfGovernment).contains(startTime));
|
||||||
Assert.assertFalse(fetcher.mandatoryQualifiers(headOfGovernment).contains(endTime));
|
Assert.assertFalse(fetcher.mandatoryQualifiers(headOfGovernment).contains(endTime));
|
||||||
Assert.assertNull(fetcher.allowedQualifiers(startTime));
|
Assert.assertNull(fetcher.allowedQualifiers(startTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSingleValue() {
|
public void testSingleValue() {
|
||||||
Assert.assertFalse(fetcher.hasSingleValue(headOfGovernment));
|
Assert.assertFalse(fetcher.hasSingleValue(headOfGovernment));
|
||||||
Assert.assertTrue(fetcher.hasSingleValue(gridId));
|
Assert.assertTrue(fetcher.hasSingleValue(gridId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDistinctValues() {
|
public void testDistinctValues() {
|
||||||
Assert.assertFalse(fetcher.hasDistinctValues(partOf));
|
Assert.assertFalse(fetcher.hasDistinctValues(partOf));
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.openrefine.wikidata.testing.TestingData;
|
import org.openrefine.wikidata.testing.TestingData;
|
||||||
@ -17,12 +40,8 @@ public class DistinctValuesScrutinizerTest extends StatementScrutinizerTest {
|
|||||||
public void testTrigger() {
|
public void testTrigger() {
|
||||||
ItemIdValue idA = TestingData.existingId;
|
ItemIdValue idA = TestingData.existingId;
|
||||||
ItemIdValue idB = TestingData.matchedId;
|
ItemIdValue idB = TestingData.matchedId;
|
||||||
ItemUpdate updateA = new ItemUpdateBuilder(idA)
|
ItemUpdate updateA = new ItemUpdateBuilder(idA).addStatement(TestingData.generateStatement(idA, idB)).build();
|
||||||
.addStatement(TestingData.generateStatement(idA, idB))
|
ItemUpdate updateB = new ItemUpdateBuilder(idB).addStatement(TestingData.generateStatement(idB, idB)).build();
|
||||||
.build();
|
|
||||||
ItemUpdate updateB = new ItemUpdateBuilder(idB)
|
|
||||||
.addStatement(TestingData.generateStatement(idB, idB))
|
|
||||||
.build();
|
|
||||||
scrutinize(updateA, updateB);
|
scrutinize(updateA, updateB);
|
||||||
assertWarningsRaised(DistinctValuesScrutinizer.type);
|
assertWarningsRaised(DistinctValuesScrutinizer.type);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
@ -9,19 +32,19 @@ public class FormatScrutinizerTest extends ValueScrutinizerTest {
|
|||||||
public EditScrutinizer getScrutinizer() {
|
public EditScrutinizer getScrutinizer() {
|
||||||
return new FormatScrutinizer();
|
return new FormatScrutinizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrigger() {
|
public void testTrigger() {
|
||||||
scrutinize(Datamodel.makeStringValue("not a number"));
|
scrutinize(Datamodel.makeStringValue("not a number"));
|
||||||
assertWarningsRaised(FormatScrutinizer.type);
|
assertWarningsRaised(FormatScrutinizer.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoIssue() {
|
public void testNoIssue() {
|
||||||
scrutinize(Datamodel.makeStringValue("1234"));
|
scrutinize(Datamodel.makeStringValue("1234"));
|
||||||
assertNoWarningRaised();
|
assertNoWarningRaised();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIncompleteMatch() {
|
public void testIncompleteMatch() {
|
||||||
scrutinize(Datamodel.makeStringValue("42 is a number"));
|
scrutinize(Datamodel.makeStringValue("42 is a number"));
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.openrefine.wikidata.qa.MockConstraintFetcher;
|
import org.openrefine.wikidata.qa.MockConstraintFetcher;
|
||||||
@ -9,7 +32,7 @@ import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
|
||||||
|
|
||||||
public class InverseConstaintScrutinizerTest extends StatementScrutinizerTest {
|
public class InverseConstaintScrutinizerTest extends StatementScrutinizerTest {
|
||||||
|
|
||||||
private ItemIdValue idA = TestingData.existingId;
|
private ItemIdValue idA = TestingData.existingId;
|
||||||
private ItemIdValue idB = TestingData.newIdB;
|
private ItemIdValue idB = TestingData.newIdB;
|
||||||
private PropertyIdValue pidWithInverse = MockConstraintFetcher.pidWithInverse;
|
private PropertyIdValue pidWithInverse = MockConstraintFetcher.pidWithInverse;
|
||||||
@ -19,20 +42,18 @@ public class InverseConstaintScrutinizerTest extends StatementScrutinizerTest {
|
|||||||
public EditScrutinizer getScrutinizer() {
|
public EditScrutinizer getScrutinizer() {
|
||||||
return new InverseConstraintScrutinizer();
|
return new InverseConstraintScrutinizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrigger() {
|
public void testTrigger() {
|
||||||
ItemUpdate update = new ItemUpdateBuilder(idA)
|
ItemUpdate update = new ItemUpdateBuilder(idA)
|
||||||
.addStatement(TestingData.generateStatement(idA, pidWithInverse, idB))
|
.addStatement(TestingData.generateStatement(idA, pidWithInverse, idB)).build();
|
||||||
.build();
|
|
||||||
scrutinize(update);
|
scrutinize(update);
|
||||||
assertWarningsRaised(InverseConstraintScrutinizer.type);
|
assertWarningsRaised(InverseConstraintScrutinizer.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoSymmetricClosure() {
|
public void testNoSymmetricClosure() {
|
||||||
ItemUpdate update = new ItemUpdateBuilder(idA)
|
ItemUpdate update = new ItemUpdateBuilder(idA).addStatement(TestingData.generateStatement(idA, inversePid, idB))
|
||||||
.addStatement(TestingData.generateStatement(idA, inversePid, idB))
|
|
||||||
.build();
|
.build();
|
||||||
scrutinize(update);
|
scrutinize(update);
|
||||||
assertNoWarningRaised();
|
assertNoWarningRaised();
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -11,58 +34,50 @@ import org.wikidata.wdtk.datamodel.interfaces.Claim;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
||||||
import org.wikidata.wdtk.datamodel.interfaces.StatementRank;
|
import org.wikidata.wdtk.datamodel.interfaces.StatementRank;
|
||||||
|
|
||||||
|
|
||||||
public class NewItemScrutinizerTest extends ScrutinizerTest {
|
public class NewItemScrutinizerTest extends ScrutinizerTest {
|
||||||
|
|
||||||
private Claim claim = Datamodel.makeClaim(TestingData.newIdA,
|
private Claim claim = Datamodel.makeClaim(TestingData.newIdA,
|
||||||
Datamodel.makeValueSnak(Datamodel.makeWikidataPropertyIdValue("P31"), TestingData.existingId),
|
Datamodel.makeValueSnak(Datamodel.makeWikidataPropertyIdValue("P31"), TestingData.existingId),
|
||||||
Collections.emptyList());
|
Collections.emptyList());
|
||||||
private Statement p31Statement = Datamodel.makeStatement(claim, Collections.emptyList(), StatementRank.NORMAL, "");
|
private Statement p31Statement = Datamodel.makeStatement(claim, Collections.emptyList(), StatementRank.NORMAL, "");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EditScrutinizer getScrutinizer() {
|
public EditScrutinizer getScrutinizer() {
|
||||||
return new NewItemScrutinizer();
|
return new NewItemScrutinizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrigger() {
|
public void testTrigger() {
|
||||||
ItemUpdate update = new ItemUpdateBuilder(TestingData.newIdA).build();
|
ItemUpdate update = new ItemUpdateBuilder(TestingData.newIdA).build();
|
||||||
scrutinize(update);
|
scrutinize(update);
|
||||||
assertWarningsRaised(
|
assertWarningsRaised(NewItemScrutinizer.noDescType, NewItemScrutinizer.noLabelType,
|
||||||
NewItemScrutinizer.noDescType,
|
NewItemScrutinizer.noTypeType, NewItemScrutinizer.newItemType);
|
||||||
NewItemScrutinizer.noLabelType,
|
|
||||||
NewItemScrutinizer.noTypeType,
|
|
||||||
NewItemScrutinizer.newItemType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmptyItem() {
|
public void testEmptyItem() {
|
||||||
ItemUpdate update = new ItemUpdateBuilder(TestingData.existingId).build();
|
ItemUpdate update = new ItemUpdateBuilder(TestingData.existingId).build();
|
||||||
scrutinize(update);
|
scrutinize(update);
|
||||||
assertNoWarningRaised();
|
assertNoWarningRaised();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGoodNewItem() {
|
public void testGoodNewItem() {
|
||||||
|
|
||||||
ItemUpdate update = new ItemUpdateBuilder(TestingData.newIdA)
|
ItemUpdate update = new ItemUpdateBuilder(TestingData.newIdA)
|
||||||
.addLabel(Datamodel.makeMonolingualTextValue("bonjour", "fr"))
|
.addLabel(Datamodel.makeMonolingualTextValue("bonjour", "fr"))
|
||||||
.addDescription(Datamodel.makeMonolingualTextValue("interesting item", "en"))
|
.addDescription(Datamodel.makeMonolingualTextValue("interesting item", "en")).addStatement(p31Statement)
|
||||||
.addStatement(p31Statement)
|
|
||||||
.build();
|
.build();
|
||||||
scrutinize(update);
|
scrutinize(update);
|
||||||
assertWarningsRaised(NewItemScrutinizer.newItemType);
|
assertWarningsRaised(NewItemScrutinizer.newItemType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletedStatements() {
|
public void testDeletedStatements() {
|
||||||
ItemUpdate update = new ItemUpdateBuilder(TestingData.newIdA)
|
ItemUpdate update = new ItemUpdateBuilder(TestingData.newIdA)
|
||||||
.addLabel(Datamodel.makeMonolingualTextValue("bonjour", "fr"))
|
.addLabel(Datamodel.makeMonolingualTextValue("bonjour", "fr"))
|
||||||
.addDescription(Datamodel.makeMonolingualTextValue("interesting item", "en"))
|
.addDescription(Datamodel.makeMonolingualTextValue("interesting item", "en")).addStatement(p31Statement)
|
||||||
.addStatement(p31Statement)
|
.deleteStatement(TestingData.generateStatement(TestingData.newIdA, TestingData.matchedId)).build();
|
||||||
.deleteStatement(TestingData.generateStatement(TestingData.newIdA,
|
|
||||||
TestingData.matchedId))
|
|
||||||
.build();
|
|
||||||
scrutinize(update);
|
scrutinize(update);
|
||||||
assertWarningsRaised(NewItemScrutinizer.newItemType, NewItemScrutinizer.deletedStatementsType);
|
assertWarningsRaised(NewItemScrutinizer.newItemType, NewItemScrutinizer.deletedStatementsType);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import org.openrefine.wikidata.testing.TestingData;
|
import org.openrefine.wikidata.testing.TestingData;
|
||||||
@ -10,19 +33,19 @@ public class NoEditsMadeScrutinizerTest extends ScrutinizerTest {
|
|||||||
public EditScrutinizer getScrutinizer() {
|
public EditScrutinizer getScrutinizer() {
|
||||||
return new NoEditsMadeScrutinizer();
|
return new NoEditsMadeScrutinizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrigger() {
|
public void testTrigger() {
|
||||||
scrutinize();
|
scrutinize();
|
||||||
assertWarningsRaised(NoEditsMadeScrutinizer.type);
|
assertWarningsRaised(NoEditsMadeScrutinizer.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonNull() {
|
public void testNonNull() {
|
||||||
scrutinize(new ItemUpdateBuilder(TestingData.newIdA).build());
|
scrutinize(new ItemUpdateBuilder(TestingData.newIdA).build());
|
||||||
assertNoWarningRaised();
|
assertNoWarningRaised();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNull() {
|
public void testNull() {
|
||||||
scrutinize(new ItemUpdateBuilder(TestingData.existingId).build());
|
scrutinize(new ItemUpdateBuilder(TestingData.existingId).build());
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Antonin Delpeuch
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
package org.openrefine.wikidata.qa.scrutinizers;
|
package org.openrefine.wikidata.qa.scrutinizers;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -16,6 +39,7 @@ import org.wikidata.wdtk.datamodel.interfaces.Statement;
|
|||||||
import org.wikidata.wdtk.datamodel.interfaces.StatementRank;
|
import org.wikidata.wdtk.datamodel.interfaces.StatementRank;
|
||||||
|
|
||||||
public class QualifierCompatibilityScrutinizerTest extends StatementScrutinizerTest {
|
public class QualifierCompatibilityScrutinizerTest extends StatementScrutinizerTest {
|
||||||
|
|
||||||
private Snak disallowedQualifier = Datamodel.makeNoValueSnak(MockConstraintFetcher.qualifierPid);
|
private Snak disallowedQualifier = Datamodel.makeNoValueSnak(MockConstraintFetcher.qualifierPid);
|
||||||
private Snak mandatoryQualifier = Datamodel.makeNoValueSnak(MockConstraintFetcher.mandatoryQualifierPid);
|
private Snak mandatoryQualifier = Datamodel.makeNoValueSnak(MockConstraintFetcher.mandatoryQualifierPid);
|
||||||
private Snak allowedQualifier = Datamodel.makeNoValueSnak(MockConstraintFetcher.allowedQualifierPid);
|
private Snak allowedQualifier = Datamodel.makeNoValueSnak(MockConstraintFetcher.allowedQualifierPid);
|
||||||
@ -24,36 +48,36 @@ public class QualifierCompatibilityScrutinizerTest extends StatementScrutinizerT
|
|||||||
public EditScrutinizer getScrutinizer() {
|
public EditScrutinizer getScrutinizer() {
|
||||||
return new QualifierCompatibilityScrutinizer();
|
return new QualifierCompatibilityScrutinizer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisallowedQualifier() {
|
public void testDisallowedQualifier() {
|
||||||
|
|
||||||
scrutinize(makeStatement(disallowedQualifier,mandatoryQualifier));
|
scrutinize(makeStatement(disallowedQualifier, mandatoryQualifier));
|
||||||
assertWarningsRaised(QualifierCompatibilityScrutinizer.disallowedQualifiersType);
|
assertWarningsRaised(QualifierCompatibilityScrutinizer.disallowedQualifiersType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMissingQualifier() {
|
public void testMissingQualifier() {
|
||||||
scrutinize(makeStatement());
|
scrutinize(makeStatement());
|
||||||
assertWarningsRaised(QualifierCompatibilityScrutinizer.missingMandatoryQualifiersType);
|
assertWarningsRaised(QualifierCompatibilityScrutinizer.missingMandatoryQualifiersType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGoodEdit() {
|
public void testGoodEdit() {
|
||||||
scrutinize(makeStatement(allowedQualifier,mandatoryQualifier));
|
scrutinize(makeStatement(allowedQualifier, mandatoryQualifier));
|
||||||
assertNoWarningRaised();
|
assertNoWarningRaised();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Statement makeStatement(Snak... qualifiers) {
|
private Statement makeStatement(Snak... qualifiers) {
|
||||||
Claim claim = Datamodel.makeClaim(TestingData.existingId,
|
Claim claim = Datamodel.makeClaim(TestingData.existingId,
|
||||||
Datamodel.makeNoValueSnak(MockConstraintFetcher.mainSnakPid), makeQualifiers(qualifiers));
|
Datamodel.makeNoValueSnak(MockConstraintFetcher.mainSnakPid), makeQualifiers(qualifiers));
|
||||||
return Datamodel.makeStatement(claim, Collections.emptyList(), StatementRank.NORMAL, "");
|
return Datamodel.makeStatement(claim, Collections.emptyList(), StatementRank.NORMAL, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SnakGroup> makeQualifiers(Snak[] qualifiers) {
|
private List<SnakGroup> makeQualifiers(Snak[] qualifiers) {
|
||||||
List<Snak> snaks = Arrays.asList(qualifiers);
|
List<Snak> snaks = Arrays.asList(qualifiers);
|
||||||
return snaks.stream()
|
return snaks.stream().map((Snak q) -> Datamodel.makeSnakGroup(Collections.<Snak> singletonList(q)))
|
||||||
.map((Snak q) -> Datamodel.makeSnakGroup(Collections.<Snak>singletonList(q)))
|
.collect(Collectors.toList());
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user