Skip to content

Commit

Permalink
Nested object structure (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
joostfarla authored Nov 22, 2023
1 parent 644975b commit 8465fc8
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 53 deletions.
10 changes: 7 additions & 3 deletions data/geo/mapping.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ objectTypeMappings:
id:
pathMappings:
path: id
surface:
pathMappings:
path: area
geometry:
pathMappings:
path: geometry
Expand Down Expand Up @@ -65,3 +62,10 @@ objectTypeMappings:
- path: isSubAddressOf/isPartOf
combiner:
type: coalesce

Dimensions:
sourceRoot: city:Building
propertyMappings:
surface:
pathMappings:
path: area
12 changes: 9 additions & 3 deletions data/geo/model.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ objectTypes:
type: String
identifier: true
cardinality: 1
surface:
type: Integer
cardinality: 0..1
geometry:
type: Geometry
cardinality: 0..1
relations:
dimensions:
target: Dimensions
cardinality: 1
hasAddress:
target: Address
cardinality: 0..*
Expand All @@ -36,3 +36,9 @@ objectTypes:
fullAddress:
type: String
cardinality: 1

Dimensions:
attributes:
surface:
type: Integer
cardinality: 0..1
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static nl.geostandaarden.imx.orchestrate.model.ModelUtils.extractKey;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -81,8 +82,23 @@ public FetchPlan<CollectionResult> plan(CollectionRequest request) {
private Set<Path> resolveSourcePaths(DataRequest request, ObjectTypeMapping typeMapping, Path basePath) {
return request.getSelectedProperties()
.stream()
.flatMap(selectedProperty -> resolveSourcePaths(selectedProperty,
typeMapping.getPropertyMapping(selectedProperty.getProperty()), basePath))
.flatMap(selectedProperty -> {
var propertyMapping = typeMapping.getPropertyMapping(selectedProperty.getProperty());

if (propertyMapping.isPresent()) {
return propertyMapping.stream()
.flatMap(mapping -> resolveSourcePaths(selectedProperty, mapping, basePath));
}

if (selectedProperty.getProperty() instanceof Relation relation) {
var targetTypeMapping = modelMapping.getObjectTypeMapping(
modelMapping.getTargetType(relation.getTarget()));
return resolveSourcePaths(selectedProperty.getNestedRequest(), targetTypeMapping, basePath)
.stream();
}

return Stream.empty();
})
.collect(toSet());
}

Expand Down Expand Up @@ -271,7 +287,8 @@ private FilterDefinition createFilterDefinition(ObjectType targetType, Map<Strin

var pathMappings = modelMapping.getObjectTypeMapping(targetType)
.getPropertyMapping(firstEntry.getKey())
.getPathMappings();
.map(PropertyMapping::getPathMappings)
.orElse(List.of());

if (pathMappings.size() > 1) {
throw new OrchestrateException("Currently only a single path mapping is supported when filtering.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,16 @@ public ObjectResult map(ObjectResult objectResult, DataRequest request) {

var property = targetType.getProperty(selectedProperty.getName());
var propertyMapping = targetMapping.getPropertyMapping(property);
var propertyResult = mapProperty(objectResult, property, propertyMapping);

// TODO: Refactor
if (!propertyMapping.isPresent()) {
var propertyValue = map(objectResult, selectedProperty.getNestedRequest())
.getProperties();
properties.put(property.getName(), propertyValue);
return;
}

var propertyResult = mapProperty(objectResult, property, propertyMapping.get());

if (propertyResult == null) {
return;
Expand Down Expand Up @@ -112,12 +121,12 @@ private Object getRelationLineageValue(Object relationValue) {
private ObjectReference getSubjectReferenceFromRelationValue(Object value) {
if (value instanceof ObjectResult objectResult && (objectResult.getLineage() != null)) {
return objectResult.getLineage()
.getOrchestratedDataElements()
.stream()
.map(OrchestratedDataElement::getSubject)
.findFirst()
.orElseThrow(() -> new OrchestrateException(
String.format("Expected data elements in relation value lineage but was %s", value)));
.getOrchestratedDataElements()
.stream()
.map(OrchestratedDataElement::getSubject)
.findFirst()
.orElseThrow(() -> new OrchestrateException(
String.format("Expected data elements in relation value lineage but was %s", value)));
}
throw new OrchestrateException(String.format("Expected object result but was %s", value));
}
Expand Down Expand Up @@ -159,9 +168,9 @@ private Object mapRelation(Object value, DataRequest request) {

private PropertyMappingResult mapProperty(ObjectResult objectResult, Property property, PropertyMapping propertyMapping) {
var pathMappingResults = propertyMapping.getPathMappings()
.stream()
.map(pathMapping -> pathMappingResult(objectResult, property, pathMapping))
.toList();
.stream()
.map(pathMapping -> pathMappingResult(objectResult, property, pathMapping))
.toList();

var combiner = propertyMapping.getCombiner();

Expand All @@ -180,16 +189,16 @@ private PropertyMappingResult mapProperty(ObjectResult objectResult, Property pr
.map(PathMappingResult::getPathMappingExecution)
.toList())
.build();

var pathResults = pathMappingResults.stream()
.map(PathMappingResult::getPathResults)
.flatMap(List::stream)
.toList();
.map(PathMappingResult::getPathResults)
.flatMap(List::stream)
.toList();

return combiner.apply(pathResults)
.withPropertyMappingExecution(propertyMappingExecution);
}

private PathMappingResult pathMappingResult(ObjectResult objectResult, Property property, PathMapping pathMapping) {
var pathResults = pathResult(objectResult, property, pathMapping.getPath(), pathMapping.getPath())
.flatMap(pathResult -> resultMapPathResult(pathResult, objectResult, property, pathMapping))
Expand Down Expand Up @@ -243,10 +252,10 @@ private Stream<PathResult> pathResult(ObjectResult objectResult, Property proper
var pathResult = PathResult.builder()
.value(propertyValue)
.pathExecution(PathExecution.builder()
.used(path)
.startNode(objectResult.getObjectReference())
.references(sourceDataElements)
.build())
.used(path)
.startNode(objectResult.getObjectReference())
.references(sourceDataElements)
.build())
.build();

return Stream.of(pathResult);
Expand Down Expand Up @@ -280,14 +289,14 @@ private Stream<PathResult> pathResult(ObjectResult objectResult, Property proper
private Stream<PathResult> resultMapPathResult(PathResult pathResult, ObjectResult objectResult, Property property, PathMapping pathMapping) {
// TODO: Lazy fetching & multi cardinality
var nextedPathResult = pathMapping.getNextPathMappings()
.stream()
.flatMap(nextPathMapping -> nextPathResults(pathResult, objectResult, property, nextPathMapping))
.findFirst()
.orElse(pathResult);
.stream()
.flatMap(nextPathMapping -> nextPathResults(pathResult, objectResult, property, nextPathMapping))
.findFirst()
.orElse(pathResult);

var mappedPathResult = pathMapping.getResultMappers()
.stream()
.reduce(nextedPathResult, (acc, resultMapper) -> resultMapper.apply(acc, property), noopCombiner());
.stream()
.reduce(nextedPathResult, (acc, resultMapper) -> resultMapper.apply(acc, property), noopCombiner());

return Stream.of(mappedPathResult);

Expand All @@ -298,7 +307,7 @@ private Stream<PathResult> nextPathResults(PathResult previousPathResult, Object

if (ifMatch != null && ifMatch.test(previousPathResult.getValue())) {
return pathMappingResult(objectResult, property, nextPathMapping)
.getPathResults().stream();
.getPathResults().stream();
}

return Stream.of(previousPathResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import java.util.Map;
import nl.geostandaarden.imx.orchestrate.engine.exchange.CollectionRequest;
import nl.geostandaarden.imx.orchestrate.engine.exchange.ObjectRequest;
import nl.geostandaarden.imx.orchestrate.engine.exchange.ObjectResult;
import nl.geostandaarden.imx.orchestrate.engine.source.DataRepository;
import nl.geostandaarden.imx.orchestrate.ext.spatial.SpatialExtension;
import nl.geostandaarden.imx.orchestrate.model.ComponentRegistry;
Expand Down Expand Up @@ -76,7 +75,9 @@ void fetch() {
.objectType("Construction")
.objectKey(Map.of("id", "B0001"))
.selectProperty("id")
.selectProperty("surface")
.selectObjectProperty("dimensions", builder -> builder
.selectProperty("surface")
.build())
.selectProperty("geometry")
.selectCollectionProperty("hasAddress", builder -> builder
.selectProperty("postalCode")
Expand Down Expand Up @@ -119,11 +120,15 @@ void fetch() {
var resultMono = engine.fetch(request);

StepVerifier.create(resultMono)
.assertNext(result -> assertThat(result).isNotNull()
.extracting(ObjectResult::getLineage)
.extracting(ObjectLineage::getOrchestratedDataElements, as(InstanceOfAssertFactories.COLLECTION))
.hasSize(4))
.expectComplete()
.verify();
.assertNext(result -> {
assertThat(result).isNotNull();
assertThat(result.getProperties())
.containsEntry("id", "B0001")
.containsEntry("dimensions", Map.of("surface", 123));
assertThat(result.getLineage())
.extracting(ObjectLineage::getOrchestratedDataElements, as(InstanceOfAssertFactories.COLLECTION))
.hasSize(3);
})
.verifyComplete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ private boolean isFilterable(ObjectType objectType, Attribute attribute) {

var pathMappings = modelMapping.getObjectTypeMapping(objectType)
.getPropertyMapping(attribute)
.getPathMappings();
.map(PropertyMapping::getPathMappings)
.orElse(List.of());

var firstPath = pathMappings.get(0)
.getPath();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ class GatewayIT {
{
construction(id: "B0002") {
id
surface
dimensions {
surface
}
hasLineage {
orchestratedDataElements {
property
Expand Down Expand Up @@ -65,9 +67,9 @@ void queryReturnsResponse_forGraphQLMediaType() {

assertThat(adres).isNotNull()
.containsEntry("id", "B0002")
.containsEntry("surface", 195)
.containsEntry("dimensions", Map.of("surface", 195))
.extractingByKey("hasLineage", as(InstanceOfAssertFactories.MAP))
.extractingByKey("orchestratedDataElements", as(InstanceOfAssertFactories.COLLECTION))
.hasSize(2);
.hasSize(1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
Expand Down Expand Up @@ -76,13 +77,17 @@ private Model resolveInverseRelations(Model model) {
.stream()
.flatMap(objectType -> objectType.getProperties(Relation.class)
.stream()
.map(relation -> {
.flatMap(relation -> {
if (relation.getInverseName() == null) {
return Stream.empty();
}

var inverseRelation = InverseRelation.builder()
.originRelation(relation)
.target(ObjectTypeRef.forType(model.getAlias(), objectType.getName()))
.build();

return Map.entry(relation.getTarget(), inverseRelation);
return Stream.of(Map.entry(relation.getTarget(), inverseRelation));
}))
.reduce(model, (acc, targetRelation) -> {
var targetObjectType = acc.getObjectType(targetRelation.getKey())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ public final class ObjectTypeMapping {
@Singular
private final Map<String, PropertyMapping> propertyMappings;

public PropertyMapping getPropertyMapping(String name) {
return Optional.ofNullable(propertyMappings.get(name))
.orElseThrow(() -> new ModelException("Attribute mapping not found: " + name));
public Optional<PropertyMapping> getPropertyMapping(String name) {
return Optional.ofNullable(propertyMappings.get(name));
}

public PropertyMapping getPropertyMapping(Property property) {
public Optional<PropertyMapping> getPropertyMapping(Property property) {
return getPropertyMapping(property.getName());
}
}

0 comments on commit 8465fc8

Please sign in to comment.