Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ class AttributeBasedRowsToAxiomsQueryResultLoader<T> implements QueryResultLoade
private Set<Axiom<?>> currentEntityAxioms = Set.of();
private NamedResource currentSubject;

private boolean typesProjected = true;

AttributeBasedRowsToAxiomsQueryResultLoader(UnitOfWork uow, Class<T> resultType, Descriptor descriptor,
EntityGraph<T> fetchGraph) {
this(uow, resultType, descriptor, fetchGraph, () -> null);
Expand All @@ -96,7 +98,8 @@ class AttributeBasedRowsToAxiomsQueryResultLoader<T> implements QueryResultLoade
this.uow = uow;
this.resultType = resultType;
this.descriptor = descriptor;
this.mappingSupplier = mappingSupplier != null ? mappingSupplier : () -> null;
assert mappingSupplier != null;
this.mappingSupplier = mappingSupplier;
this.entityType = uow.getMetamodel().entity(resultType);
this.fetchGraph = fetchGraph;
}
Expand All @@ -113,6 +116,7 @@ private void createProjectionMappings(List<String> projectedVars) {
if (mappings != null) {
return;
}
this.typesProjected = false;
assert !projectedVars.isEmpty();
final String subjectVar = projectedVars.get(0);
this.mappings = new ArrayList<>(projectedVars.size() - 1);
Expand All @@ -126,9 +130,11 @@ private void createProjectionMappings(List<String> projectedVars) {
} else if (atts.containsKey(projectedVar.substring(subjectVar.length() + 1))) {
// ?x_stringAttribute
mappings.add(new QueryVariableMapping(subjectVar, projectedVar, atts.get(projectedVar.substring(subjectVar.length() + 1))));
} else if (projectedVar.endsWith(AttributeEnumeratingSparqlAssemblyModifier.TYPES_VAR_NAME)) {
} else if (projectedVar.endsWith(AttributeEnumeratingSparqlAssemblyModifier.TYPES_VAR_NAME) || (entityType.getTypes() != null && projectedVar.endsWith(entityType.getTypes()
.getName()))) {
// ?x_types or ?types
mappings.add(new QueryVariableMapping(subjectVar, projectedVar, entityType.getTypes()));
this.typesProjected = true;
} else {
LOG.warn("Variable '{}' projected from the query cannot be mapped to any attributes in entity class {}.", projectedVar, entityType);
}
Expand Down Expand Up @@ -209,6 +215,10 @@ private Stream<Value<?>> extractValue(ResultRow row,
}

private T loadEntity() {
if (!typesProjected) {
currentEntityAxioms.add(new AxiomImpl<>(currentSubject,
Assertion.createClassAssertion(false), new Value<>(entityType.getIRI().toURI())));
}
try {
return uow.readObjectFromAxioms(resultType, currentEntityAxioms, new AxiomBasedLoadingConfigGroup<>(currentSubject.getIdentifier(), descriptor, fetchGraph));
} catch (CardinalityConstraintViolatedException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import cz.cvut.kbss.jopa.environment.OWLClassA;
import cz.cvut.kbss.jopa.environment.OWLClassD;
import cz.cvut.kbss.jopa.environment.Phone;
import cz.cvut.kbss.jopa.environment.Vocabulary;
import cz.cvut.kbss.jopa.environment.utils.Generators;
import cz.cvut.kbss.jopa.environment.utils.MetamodelMocks;
Expand All @@ -32,6 +33,7 @@
import cz.cvut.kbss.jopa.model.metamodel.IdentifiableEntityType;
import cz.cvut.kbss.jopa.sessions.UnitOfWork;
import cz.cvut.kbss.jopa.sessions.util.AxiomBasedLoadingConfigGroup;
import cz.cvut.kbss.ontodriver.ResultSet;
import cz.cvut.kbss.ontodriver.exception.OntoDriverException;
import cz.cvut.kbss.ontodriver.iteration.ResultRow;
import cz.cvut.kbss.ontodriver.model.Assertion;
Expand Down Expand Up @@ -154,7 +156,8 @@ void loadLastPendingLoadsLastPendingEntity() throws Exception {
verify(uow).readObjectFromAxioms(eq(OWLClassA.class), anyCollection(), eq(new AxiomBasedLoadingConfigGroup<>(instance.getUri(), descriptor, fetchGraph)));
}

private AttributeBasedRowsToAxiomsQueryResultLoader<OWLClassA> createOwlClassASut(EntityGraph<OWLClassA> fetchGraph) {
private AttributeBasedRowsToAxiomsQueryResultLoader<OWLClassA> createOwlClassASut(
EntityGraph<OWLClassA> fetchGraph) {
final List<QueryVariableMapping> mappings = List.of(
new QueryVariableMapping("x", "x_stringAttribute", metamodelMocks.forOwlClassA().stringAttribute()),
new QueryVariableMapping("x", "x_types", metamodelMocks.forOwlClassA().typesSpec())
Expand Down Expand Up @@ -300,4 +303,32 @@ void loadResultSupportsGroupConcatenatedTypes() throws Exception {
.anyMatch(ax -> ax.getValue().stringValue().equals(instance.getStringAttribute())));
}

@Test
void loadResultAutomaticallyAddsClassAssertionForDirectEntityMappingWithoutProjectedTypes() throws Exception {
final AttributeBasedRowsToAxiomsQueryResultLoader<Phone> sut = new AttributeBasedRowsToAxiomsQueryResultLoader<>(uow, Phone.class, descriptor, null);
final Phone phone = new Phone(Generators.createIndividualIdentifier(), "123456789", "Nokia");
final List<String> columnNames = List.of("x", "x_number", "x_brand");
final ResultSet resultSet = mock(ResultSet.class);
when(resultSet.getColumnNames()).thenReturn(columnNames);
final ResultRow row = mock(ResultRow.class);
when(row.getColumnCount()).thenReturn(3);
when(row.getColumnNames()).thenReturn(columnNames);
when(row.isBound("x")).thenReturn(true);
when(row.getObject(0, URI.class)).thenReturn(phone.getUri());
when(row.getObject("x", URI.class)).thenReturn(phone.getUri());
when(row.isBound("x_number")).thenReturn(true);
when(row.getObject("x_number")).thenReturn(phone.getNumber());
when(row.isBound("x_brand")).thenReturn(true);
when(row.getObject("x_brand")).thenReturn(phone.getBrand());
when(uow.readObjectFromAxioms(eq(Phone.class), anyCollection(), any(AxiomBasedLoadingConfigGroup.class))).thenReturn(phone);

sut.init(resultSet);
final Optional<Phone> intermediate = sut.loadResult(row);
assertFalse(intermediate.isPresent());
final Optional<Phone> result = sut.loadLastPending();
assertTrue(result.isPresent());
final ArgumentCaptor<Collection<Axiom<?>>> captor = ArgumentCaptor.forClass(Collection.class);
verify(uow).readObjectFromAxioms(eq(Phone.class), captor.capture(), any(AxiomBasedLoadingConfigGroup.class));
assertThat(captor.getValue(), hasItem(new AxiomImpl<>(NamedResource.create(phone.getUri()), Assertion.createClassAssertion(false), new Value<>(URI.create(Vocabulary.c_Phone)))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,8 @@ public void querySupportsFetchGraphs() {
.getResultList();
assertEquals(entities.size(), result.size());
result.forEach(c -> {
final Optional<OWLClassV> expected = entities.stream().filter(v -> v.getUri().equals(c.getUri())).findFirst();
final Optional<OWLClassV> expected = entities.stream().filter(v -> v.getUri().equals(c.getUri()))
.findFirst();
assertTrue(expected.isPresent());
assertEquals(expected.get().getName(), c.getName());
assertEquals(expected.get().getDescription(), c.getDescription());
Expand All @@ -482,4 +483,24 @@ public void querySupportsFetchGraphs() {
});
});
}

@Test
public void querySupportsMappingResultsDirectlyToEntityWithoutProjectingTypes() {
final List<OWLClassE> entities = QueryTestEnvironment.getData(OWLClassE.class);
final List<OWLClassE> result = getEntityManager().createNativeQuery("""
SELECT ?x ?stringAttribute WHERE {
?x a ?type ;
?hasString ?stringAttribute .
}""", OWLClassE.class)
.setParameter("type", URI.create(Vocabulary.C_OWL_CLASS_E))
.setParameter("hasString", URI.create(Vocabulary.P_E_STRING_ATTRIBUTE))
.getResultList();
entities.sort(Comparator.comparing(OWLClassE::getUri));
result.sort(Comparator.comparing(OWLClassE::getUri)); // Sort here instead of in the query due to OWL2Query lacking proper sorting support
assertEquals(entities.size(), result.size());
for (int i = 0; i < entities.size(); i++) {
assertEquals(entities.get(i).getUri(), result.get(i).getUri());
assertEquals(entities.get(i).getStringAttribute(), result.get(i).getStringAttribute());
}
}
}