diff --git a/backend/molgenis-emx2-rdf/src/main/java/org/molgenis/emx2/rdf/RDFService.java b/backend/molgenis-emx2-rdf/src/main/java/org/molgenis/emx2/rdf/RDFService.java index 1c32f87c36..b3d948a848 100644 --- a/backend/molgenis-emx2-rdf/src/main/java/org/molgenis/emx2/rdf/RDFService.java +++ b/backend/molgenis-emx2-rdf/src/main/java/org/molgenis/emx2/rdf/RDFService.java @@ -186,26 +186,31 @@ public void describeAsRDF( describeRoot(builder); } + // Collect all tables present in selected schemas. + Set allTables = new HashSet<>(); + for (final Schema schema : schemas) { if (table == null) { describeSchema(builder, schema); } - final List
tables = table != null ? Arrays.asList(table) : schema.getTablesSorted(); - for (final Table tableToDescribe : tables) { - // for full-schema retrieval, don't print the (huge and mostly unused) ontologies - // of course references to ontologies are still included and are fully retrievable - if (table == null - && tableToDescribe.getMetadata().getTableType().equals(TableType.ONTOLOGIES)) { - continue; - } - if (rowId == null) { - describeTable(builder, tableToDescribe); - describeColumns(builder, tableToDescribe, columnName); - } - // if a column name is provided then only provide column metadata, no row values - if (columnName == null) { - rowsToRdf(builder, tableToDescribe, rowId); - } + allTables.addAll(schema.getTablesSorted()); + } + + final Set
tables = table != null ? tablesToDescribe(allTables, table) : allTables; + for (final Table tableToDescribe : tables) { + // for full-schema retrieval, don't print the (huge and mostly unused) ontologies + // of course references to ontologies are still included and are fully retrievable + if (table == null + && tableToDescribe.getMetadata().getTableType().equals(TableType.ONTOLOGIES)) { + continue; + } + if (rowId == null) { + describeTable(builder, tableToDescribe); + describeColumns(builder, tableToDescribe, columnName); + } + // if a column name is provided then only provide column metadata, no row values + if (columnName == null) { + rowsToRdf(builder, tableToDescribe, rowId); } } Rio.write(builder.build(), outputStream, rdfFormat, config); @@ -215,6 +220,31 @@ public void describeAsRDF( } } + private Set
tablesToDescribe(Set
allTables, Table tableFilter) { + Set
tablesToDescribe = new HashSet<>(); + for (Table currentTable : allTables) { + processInheritedTable(tableFilter, tablesToDescribe, currentTable); + } + return tablesToDescribe; + } + + private boolean processInheritedTable( + Table tableFilter, Set
tablesToDescribe, Table currentTable) { + if (currentTable == null) { + return false; + } + if (currentTable.getSchema().getName().equals(tableFilter.getSchema().getName()) + && currentTable.getName().equals(tableFilter.getName())) { + tablesToDescribe.add(currentTable); + return true; + } + if (processInheritedTable(tableFilter, tablesToDescribe, currentTable.getInheritedTable())) { + tablesToDescribe.add(currentTable); + return true; + } + return false; + } + private void addModelToBuilder(ModelBuilder builder, Model model) { model.getNamespaces().forEach(builder::setNamespace); model.forEach(e -> builder.add(e.getSubject(), e.getPredicate(), e.getObject())); diff --git a/backend/molgenis-emx2-rdf/src/test/java/org/molgenis/emx2/rdf/RDFTest.java b/backend/molgenis-emx2-rdf/src/test/java/org/molgenis/emx2/rdf/RDFTest.java index 61ead5be52..51a19fddd5 100644 --- a/backend/molgenis-emx2-rdf/src/test/java/org/molgenis/emx2/rdf/RDFTest.java +++ b/backend/molgenis-emx2-rdf/src/test/java/org/molgenis/emx2/rdf/RDFTest.java @@ -10,14 +10,19 @@ import java.io.IOException; import java.io.OutputStream; import java.io.StringReader; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; -import org.eclipse.rdf4j.model.Literal; +import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Namespace; +import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.Triple; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.impl.SimpleNamespace; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.util.Values; import org.eclipse.rdf4j.model.vocabulary.OWL; import org.eclipse.rdf4j.model.vocabulary.RDF; @@ -51,6 +56,8 @@ public class RDFTest { static Schema petStore_nr2; static Schema compositeKeyTest; static Schema ontologyTest; + static Schema tableInherTest; + static Schema tableInherExtTest; final Set DEFAULT_NAMESPACES = new HashSet<>() { @@ -162,6 +169,62 @@ public static void setup() { "C00-C75 Malignant neoplasms, stated or presumed to be primary, of specified sites, except of lymphoid, haematopoietic and related tissue", "code", "C00-C14")); + + // Test table inheritance + // Use example from the catalogue schema since this has all the different issues. + tableInherTest = database.dropCreateSchema("tableInheritanceTest"); + tableInherTest.create( + table( + "Root", + column("id", ColumnType.STRING).setKey(1), + column("rootColumn", ColumnType.STRING))); + tableInherTest.create(table("Child", column("childColumn")).setInheritName("Root")); + // Same column name but not in shared parent, so test how this is handled. + tableInherTest.create( + table("GrandchildTypeA", column("grandchildColumn")).setInheritName("Child")); + tableInherTest.create( + table("GrandchildTypeB", column("grandchildColumn")).setInheritName("Child")); + tableInherTest.getTable("Root").insert(row("id", "1", "rootColumn", "id1 data")); + tableInherTest.getTable("Child").insert(row("id", "2", "childColumn", "id2 data")); + tableInherTest + .getTable("GrandchildTypeA") + .insert(row("id", "3", "grandchildColumn", "id3 data")); + tableInherTest + .getTable("GrandchildTypeB") + .insert( + row( + "id", + "4", + "rootColumn", + "id4 data for rootColumn", + "childColumn", + "id4 data for childColumn", + "grandchildColumn", + "id4 data")); + + // Test for table that extends table from different schema + tableInherExtTest = database.createSchema("tableInheritanceExternalSchemaTest"); + tableInherExtTest.create( + table("ExternalChild", column("externalChildColumn")) + .setImportSchema(tableInherTest.getName()) + .setInheritName("Root")); + tableInherExtTest.create( + table("ExternalGrandchild", column("externalGrandchildColumn")) + .setInheritName("ExternalChild")); + tableInherExtTest.create( + table( + "ExternalUnrelated", + column("id", ColumnType.STRING).setKey(1), + column("externalUnrelatedColumn"))); + tableInherExtTest + .getTable("ExternalChild") + .insert(row("id", "5", "externalChildColumn", "id5 data")); + tableInherExtTest + .getTable("ExternalGrandchild") + .insert(row("id", "6", "externalGrandchildColumn", "id6 data")); + tableInherExtTest + .getTable("ExternalUnrelated") + .insert(row("id", "a", "externalUnrelatedColumn", "unrelated data")); } @AfterAll @@ -171,6 +234,8 @@ public static void tearDown() { database.dropSchema(petStore_nr2.getName()); database.dropSchema(compositeKeyTest.getName()); database.dropSchema(ontologyTest.getName()); + database.dropSchema(tableInherExtTest.getName()); + database.dropSchema(tableInherTest.getName()); } @Test @@ -431,58 +496,316 @@ void testThatURLsAreNotSplitForOntologyParentItem() throws IOException { } @Test - void testThatSameColumnIRIisAlwaysUsed() throws IOException { - // Use example from the catalogue schema since this has all the different issues. - var schema = database.dropCreateSchema("iriTest"); - schema.create( - table( - "Resources", - column("id", ColumnType.STRING).setKey(1), - column("website", ColumnType.HYPERLINK))); - schema.create(table("Extended Resources").setInheritName("Resources")); - Table dataResources = - schema.create(table("Data Resources", column("data")).setInheritName("Extended Resources")); - - var handler = new InMemoryRDFHandler() {}; - getAndParseRDF(Selection.of(schema), handler); - // The table Data Resources extends Extended Resources, which extends Resources. - // Resources defines the column website. There should only be one predicate for - // Resources/column/website and the other tables should use this predicate. - var websitePredicate = - Values.iri("http://localhost:8080/iriTest/api/rdf/Resources/column/website"); - var websitePredicateER = - Values.iri("http://localhost:8080/iriTest/api/rdf/ExtendedResources/column/website"); - var websitePredicateDR = - Values.iri("http://localhost:8080/iriTest/api/rdf/DataResources/column/website"); + void testTableInheritanceAlwaysSamePredicate() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherTest, tableInherExtTest), handler); + // All should use the same predicate for rootColumn: + // Root (is root of all inheritance) + // Child extends Root + // GrandChildTypeA extends Child + // GrandChildTypeB extends Child + // ExternalChild extends Root + // ExternalGrandchild extends ExternalChild + assertAll( + () -> + assertTrue( + handler.resources.containsKey( + Values.iri( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root/column/rootColumn")), + "There should be a predicate for the rootColumn in the Root table"), + () -> + assertFalse( + handler.resources.containsKey( + Values.iri( + "http://localhost:8080/tableInheritanceTest/api/rdf/Child/column/rootColumn")), + "There should not be a predicate for the rootColumn in the Child table"), + () -> + assertFalse( + handler.resources.containsKey( + Values.iri( + "http://localhost:8080/tableInheritanceTest/api/rdf/GrandchildTypeA/column/rootColumn")), + "There should not be a predicate for the rootColumn in the GrandchildTypeA table"), + () -> + assertFalse( + handler.resources.containsKey( + Values.iri( + "http://localhost:8080/tableInheritanceTest/api/rdf/GrandchildTypeB/column/rootColumn")), + "There should not be a predicate for the rootColumn in the GrandchildTypeB table"), + () -> + assertFalse( + handler.resources.containsKey( + Values.iri( + "http://localhost:8080/tableInheritanceTest/api/rdf/ExternalChild/column/rootColumn")), + "There should not be a predicate for the rootColumn in the ExternalChild table"), + () -> + assertFalse( + handler.resources.containsKey( + Values.iri( + "http://localhost:8080/tableInheritanceTest/api/rdf/ExternalGrandchild/column/rootColumn")), + "There should not be a predicate for the rootColumn in the ExternalGrandchild table")); + } - assertTrue( - handler.resources.containsKey(websitePredicate), - "There should be a predicate for the column in the Resources (base) table"); - assertFalse( - handler.resources.containsKey(websitePredicateER), - "There should not be a predicate for the column in the Extended Resources table"); - assertFalse( - handler.resources.containsKey(websitePredicateDR), - "There should not be a predicate for the column in the Data Resources table"); + @Test + void testTableInheritanceRetrieveData() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherTest), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, true), + Map.entry(ValidationTriple.ID2, true), + Map.entry(ValidationTriple.ID3, true), + Map.entry(ValidationTriple.ID4, true), + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), + Map.entry(ValidationTriple.ID5, false), // different schema + Map.entry(ValidationTriple.ID6, false), // different schema + Map.entry(ValidationTriple.UNRELATED, false) // different schema + )); + } - dataResources.insert(row("id", "demo1", "data", "my data")); - getAndParseRDF(Selection.ofRow(schema, "Resources", "id=demo1"), handler); - var columnPredicate = - Values.iri("http://localhost:8080/iriTest/api/rdf/DataResources/column/data"); - assertTrue( - handler.resources.containsKey(columnPredicate), "should include the subclass column"); - var dataValue = - ((Literal) - handler - .resources - .get(Values.iri("http://localhost:8080/iriTest/api/rdf/Resources?id=demo1")) - .get( - Values.iri( - "http://localhost:8080/iriTest/api/rdf/DataResources/column/data")) - .toArray()[0]) - .stringValue(); - assertEquals("my data", dataValue); - database.dropSchema(schema.getName()); + @Test + void testTableInheritanceRetrieveDataWithTableRoot() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherTest, "Root"), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, true), + Map.entry(ValidationTriple.ID2, true), + Map.entry(ValidationTriple.ID3, true), + Map.entry(ValidationTriple.ID4, true), + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), + Map.entry(ValidationTriple.ID5, false), // different schema + Map.entry(ValidationTriple.ID6, false), // different schema + Map.entry(ValidationTriple.UNRELATED, false) // different schema + )); + } + + @Test + void testTableInheritanceRetrieveDataWithTableChild() throws IOException { + // All subjects still use Root IRIs but offers a way to "filter out parent triples". + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherTest, "Child"), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // parent of selected table + Map.entry(ValidationTriple.ID2, true), + Map.entry(ValidationTriple.ID3, true), // child + Map.entry(ValidationTriple.ID4, true), // child + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), // child + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), // child + Map.entry(ValidationTriple.ID5, false), // different schema + Map.entry(ValidationTriple.ID6, false), // different schema + Map.entry(ValidationTriple.UNRELATED, false) // different schema + )); + } + + @Test + void testTableInheritanceRetrieveDataWithTableGrandchildTypeA() throws IOException { + // All subjects still use Root IRIs but offers a way to "filter out parent triples". + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherTest, "GrandchildTypeA"), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // grandparent of selected table + Map.entry(ValidationTriple.ID2, false), // parent of selected table + Map.entry(ValidationTriple.ID3, true), + Map.entry(ValidationTriple.ID4, false), // sibling of selected table + Map.entry(ValidationTriple.ID4_PARENT_FIELD, false), // sibling of selected table + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, false), // sibling of selected table + Map.entry(ValidationTriple.ID5, false), // different schema + Map.entry(ValidationTriple.ID6, false), // different schema + Map.entry(ValidationTriple.UNRELATED, false) // different schema + )); + } + + @Test + void testTableInheritanceRetrieveDataWithTableGrandchildTypeB() throws IOException { + // All subjects still use Root IRIs but offers a way to "filter out parent triples". + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherTest, "GrandchildTypeB"), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // grandparent of selected table + Map.entry(ValidationTriple.ID2, false), // parent of selected table + Map.entry(ValidationTriple.ID3, false), // sibling of selected table + Map.entry(ValidationTriple.ID4, true), + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), + Map.entry(ValidationTriple.ID5, false), // different schema + Map.entry(ValidationTriple.ID6, false), // different schema + Map.entry(ValidationTriple.UNRELATED, false) // different schema + )); + } + + @Test + void testTableInheritanceRetrieveDataWithRowId() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.ofRow(tableInherTest, "Root", "id=4"), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // not selected + Map.entry(ValidationTriple.ID2, false), // not selected + Map.entry(ValidationTriple.ID3, false), // not selected + Map.entry(ValidationTriple.ID4, true), + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), + Map.entry(ValidationTriple.ID5, false), // not selected + Map.entry(ValidationTriple.ID6, false), // not selected + Map.entry(ValidationTriple.UNRELATED, false) // not selected + )); + } + + @Test + void testTableInheritanceExternalSchemaRetrieveData() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherExtTest), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // different schema + Map.entry(ValidationTriple.ID2, false), // different schema + Map.entry(ValidationTriple.ID3, false), // different schema + Map.entry(ValidationTriple.ID4, false), // different schema + Map.entry(ValidationTriple.ID4_PARENT_FIELD, false), // different schema + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, false), // different schema + Map.entry(ValidationTriple.ID5, true), + Map.entry(ValidationTriple.ID6, true), + Map.entry(ValidationTriple.UNRELATED, true))); + } + + @Test + void testTableInheritanceExternalSchemaDataWithTableExternalChild() throws IOException { + // Note that even though the subject has an ID IRI based on table Root, this table is not part + // of the selected scheme so this table cannot be selected: + // `tableInherExtTest.getTable("Root")` == `null` + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherExtTest, "ExternalChild"), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // different schema + Map.entry(ValidationTriple.ID2, false), // different schema + Map.entry(ValidationTriple.ID3, false), // different schema + Map.entry(ValidationTriple.ID4, false), // different schema + Map.entry(ValidationTriple.ID4_PARENT_FIELD, false), // different schema + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, false), // different schema + Map.entry(ValidationTriple.ID5, true), + Map.entry(ValidationTriple.ID6, true), + Map.entry(ValidationTriple.UNRELATED, false))); // not part of inheritance + } + + @Test + void testTableInheritanceExternalSchemaDataWithRowId() throws IOException { + // Note that even though the subject has an ID IRI based on table Root, this table is not part + // of the selected scheme so this table cannot be selected: + // `tableInherExtTest.getTable("Root")` == `null` + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.ofRow(tableInherExtTest, "ExternalChild", "id=5"), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // not selected + Map.entry(ValidationTriple.ID2, false), // not selected + Map.entry(ValidationTriple.ID3, false), // not selected + Map.entry(ValidationTriple.ID4, false), // not selected + Map.entry(ValidationTriple.ID4_PARENT_FIELD, false), // not selected + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, false), // not selected + Map.entry(ValidationTriple.ID5, true), + Map.entry(ValidationTriple.ID6, false), // not selected + Map.entry(ValidationTriple.UNRELATED, false) // not selected + )); + } + + @Test + void testTableInheritanceRetrieveDataMultiSchema() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF(Selection.of(tableInherTest, tableInherExtTest), handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, true), + Map.entry(ValidationTriple.ID2, true), + Map.entry(ValidationTriple.ID3, true), + Map.entry(ValidationTriple.ID4, true), + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), + Map.entry(ValidationTriple.ID5, true), + Map.entry(ValidationTriple.ID6, true), + Map.entry(ValidationTriple.UNRELATED, true))); + } + + @Test + void testTableInheritanceRetrieveDataMultiSchemaWithTableRoot() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF( + Selection.of( + new Schema[] {tableInherTest, tableInherExtTest}, tableInherTest.getTable("Root")), + handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, true), + Map.entry(ValidationTriple.ID2, true), + Map.entry(ValidationTriple.ID3, true), + Map.entry(ValidationTriple.ID4, true), + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), + Map.entry(ValidationTriple.ID5, true), + Map.entry(ValidationTriple.ID6, true), + Map.entry(ValidationTriple.UNRELATED, false))); // not part of inheritance + } + + @Test + void testTableInheritanceRetrieveDataMultiSchemaWithRowId() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF( + Selection.ofRow( + new Schema[] {tableInherTest, tableInherExtTest}, + tableInherTest.getTable("Root"), + "id=4"), + handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // not selected + Map.entry(ValidationTriple.ID2, false), // not selected + Map.entry(ValidationTriple.ID3, false), // not selected + Map.entry(ValidationTriple.ID4, true), + Map.entry(ValidationTriple.ID4_PARENT_FIELD, true), + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, true), + Map.entry(ValidationTriple.ID5, false), // not selected + Map.entry(ValidationTriple.ID6, false), // not selected + Map.entry(ValidationTriple.UNRELATED, false))); // not selected + } + + @Test + void testTableInheritanceRetrieveDataMultiSchemaWithExternalRowId() throws IOException { + var handler = new InMemoryRDFHandler() {}; + getAndParseRDF( + Selection.ofRow( + new Schema[] {tableInherTest, tableInherExtTest}, + tableInherTest.getTable("Root"), + "id=5"), + handler); + assertPresence( + handler, + Map.ofEntries( + Map.entry(ValidationTriple.ID1, false), // not selected + Map.entry(ValidationTriple.ID2, false), // not selected + Map.entry(ValidationTriple.ID3, false), // not selected + Map.entry(ValidationTriple.ID4, false), // not selected + Map.entry(ValidationTriple.ID4_PARENT_FIELD, false), // not selected + Map.entry(ValidationTriple.ID4_GRANDPARENT_FIELD, false), // not selected + Map.entry(ValidationTriple.ID5, true), + Map.entry(ValidationTriple.ID6, false), // not selected + Map.entry(ValidationTriple.UNRELATED, false))); // not selected } @Test @@ -900,6 +1223,12 @@ static Selection of(Schema schema, String table) { return selection; } + static Selection of(Schema[] schema, Table table) { + var selection = Selection.of(schema); + selection.table = table; + return selection; + } + static Selection of(Schema schema, String table, String columnName) { var selection = Selection.of(schema, table); selection.columnName = columnName; @@ -911,5 +1240,111 @@ static Selection ofRow(Schema schema, String table, String rowId) { selection.rowId = rowId; return selection; } + + static Selection ofRow(Schema[] schema, Table table, String rowId) { + var selection = Selection.of(schema, table); + selection.rowId = rowId; + return selection; + } + } + + void assertPresence(InMemoryRDFHandler handler, Map presenceMap) { + // Tracks errors. + List errors = new ArrayList<>(); + + for (ValidationTriple triple : presenceMap.keySet()) { + Map> predicates = handler.resources.get(triple.getSubject()); + // If Triple should be present in handler. + if (presenceMap.get(triple)) { + if (predicates == null) { + errors.add("Missing predicates for subject: " + triple.getSubject()); + continue; + } + Set objects = predicates.get(triple.getPredicate()); + if (objects == null) { + errors.add("Missing objects for predicate: " + triple.getPredicate()); + continue; + } + if (objects.size() != 1) { + errors.add("Only 1 object should be present for: " + triple.getPredicate()); + } + Object firstObject = objects.toArray()[0]; + if (!triple.getObject().equals(firstObject)) { + errors.add( + "First object not equal to expected value. Found \"" + + firstObject + + "\", but should be \"" + + triple.getObject() + + "\""); + } + } // If Triple should not be present in handler. + else { + if (predicates != null) + errors.add("Found predicates while expecting none for subject: " + triple.getSubject()); + } + } + + // Compares error ArrayList to empty one so actual messages are shown if any are found. + assertEquals(new ArrayList<>(), errors); + } + + private enum ValidationTriple { + ID1( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=1", + "http://localhost:8080/tableInheritanceTest/api/rdf/Root/column/rootColumn", + "id1 data"), + ID2( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=2", + "http://localhost:8080/tableInheritanceTest/api/rdf/Child/column/childColumn", + "id2 data"), + ID3( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=3", + "http://localhost:8080/tableInheritanceTest/api/rdf/GrandchildTypeA/column/grandchildColumn", + "id3 data"), + ID4( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=4", + "http://localhost:8080/tableInheritanceTest/api/rdf/GrandchildTypeB/column/grandchildColumn", + "id4 data"), + ID4_GRANDPARENT_FIELD( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=4", + "http://localhost:8080/tableInheritanceTest/api/rdf/Root/column/rootColumn", + "id4 data for rootColumn"), + ID4_PARENT_FIELD( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=4", + "http://localhost:8080/tableInheritanceTest/api/rdf/Child/column/childColumn", + "id4 data for childColumn"), + ID5( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=5", + "http://localhost:8080/tableInheritanceExternalSchemaTest/api/rdf/ExternalChild/column/externalChildColumn", + "id5 data"), + ID6( + "http://localhost:8080/tableInheritanceTest/api/rdf/Root?id=6", + "http://localhost:8080/tableInheritanceExternalSchemaTest/api/rdf/ExternalGrandchild/column/externalGrandchildColumn", + "id6 data"), + UNRELATED( + "http://localhost:8080/tableInheritanceExternalSchemaTest/api/rdf/ExternalUnrelated?id=a", + "http://localhost:8080/tableInheritanceExternalSchemaTest/api/rdf/ExternalUnrelated/column/externalUnrelatedColumn", + "unrelated data"); + + private final Triple triple; + + public Resource getSubject() { + return triple.getSubject(); + } + + public IRI getPredicate() { + return triple.getPredicate(); + } + + public Value getObject() { + return triple.getObject(); + } + + ValidationTriple(String subjectUrl, String predicateUrl, String objectString) { + this.triple = + SimpleValueFactory.getInstance() + .createTriple( + Values.iri(subjectUrl), Values.iri(predicateUrl), Values.literal(objectString)); + } } }