Skip to content

Commit

Permalink
WIP inner join
Browse files Browse the repository at this point in the history
  • Loading branch information
stempler committed Feb 7, 2024
1 parent 8a831f1 commit c6e943c
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public interface JoinFunction {
*/
public static final String PARAMETER_JOIN = "join";

/**
* Name of the parameter that specifies if an inner join should be
* performed.
*/
public static final String PARAMETER_INNER_JOIN = "innerJoin";

/**
* the join function Id
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2024 wetransform GmbH
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* wetransform GmbH <http://www.wetransform.to>
*/

package eu.esdihumboldt.hale.common.instance.model.impl;

import java.util.Iterator;
import java.util.NoSuchElementException;

import eu.esdihumboldt.hale.common.instance.model.ResourceIterator;

/**
* {@link ResourceIterator} adapter for a normal iterator that can perform a
* conversion from the iterator elements to a target element type. It filters
* out items that are converted to a <code>null</code> value.
*
* @param <S> the source object type served by the wrapped iterator
* @param <T> the object type served by the resource iterator
* @author Simon Templer
*/
public abstract class FilterResourceIteratorAdapter<S, T> implements ResourceIterator<T> {

/**
* The next matching instance
*/
private T preview;

/**
* States if the value in {@link #preview} represents a valid element
*/
private boolean previewPresent;

/**
* States if {@link #preview}/{@link #previewPresent} must be updated
*/
private boolean updatePreview = true;

private final Iterator<S> iterator;

/**
* Create a {@link ResourceIterator} adapter for the given iterator.
*
* @param iterator the iterator to adapt
*/
public FilterResourceIteratorAdapter(Iterator<S> iterator) {
super();
this.iterator = iterator;
}

@Override
public boolean hasNext() {
update(); // ensure previewPresent/preview are set

return previewPresent;
}

@Override
public T next() {
update(); // ensure previewPresent/preview are set

if (!previewPresent) {
throw new NoSuchElementException();
}

updatePreview = true; // next time, update the preview

return preview;
}

/**
* Move {@link #preview} to the next non-null converted item if possible,
* update {@link #previewPresent}.
*/
private void update() {
if (updatePreview) {
previewPresent = false;

// find first instance matching the filter
while (!previewPresent && iterator.hasNext()) {
S item = iterator.next();
T converted = convert(item);

if (converted != null) {
previewPresent = true;
preview = converted;
}
}

if (!previewPresent) {
preview = null;
}

updatePreview = false;
}
}

@Override
public void remove() {
throw new UnsupportedOperationException(
"Removing instances not supported on filtered collections");
}

/**
* Convert an object before it is returned by {@link #next()}.
*
* @param next the object to convert
* @return the converted object or null if it should be skipped
*/
protected abstract T convert(S next);

/**
* @see ResourceIterator#close()
*/
@Override
public void close() {
if (iterator instanceof ResourceIterator<?>) {
((ResourceIterator<?>) iterator).close();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public ResourceIterator<FamilyInstance> partitionInstances(InstanceCollection in
String transformationIdentifier, TransformationEngine engine,
ListMultimap<String, ParameterValue> transformationParameters,
Map<String, String> executionParameters, TransformationLog log)
throws TransformationException {
throws TransformationException {
if (transformationParameters == null
|| !transformationParameters.containsKey(PARAMETER_JOIN)
|| transformationParameters.get(PARAMETER_JOIN).isEmpty()) {
Expand Down Expand Up @@ -121,7 +121,13 @@ public ResourceIterator<FamilyInstance> partitionInstances(InstanceCollection in
iterator.close();
}

boolean innerJoin = false; // default to false if not specified
List<ParameterValue> innerJoinValues = transformationParameters.get(PARAMETER_INNER_JOIN);
if (!innerJoinValues.isEmpty()) {
innerJoin = innerJoinValues.get(0).as(Boolean.class, innerJoin);
}

return new JoinIterator(instances, startInstances, joinDefinition.directParent, index,
joinDefinition.joinTable, valueProcessor);
joinDefinition.joinTable, valueProcessor, innerJoin);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@
import eu.esdihumboldt.hale.common.instance.model.InstanceCollection;
import eu.esdihumboldt.hale.common.instance.model.InstanceReference;
import eu.esdihumboldt.hale.common.instance.model.ResolvableInstanceReference;
import eu.esdihumboldt.hale.common.instance.model.impl.GenericResourceIteratorAdapter;
import eu.esdihumboldt.hale.common.instance.model.impl.FilterResourceIteratorAdapter;

/**
* Iterator used by {@link JoinHandler}
*
* @author Florian Esser
*/
class JoinIterator extends GenericResourceIteratorAdapter<InstanceReference, FamilyInstance> {
class JoinIterator extends FilterResourceIteratorAdapter<InstanceReference, FamilyInstance> {

private final InstanceCollection instances;
// type -> direct-parent
Expand All @@ -51,35 +51,43 @@ class JoinIterator extends GenericResourceIteratorAdapter<InstanceReference, Fam

private final ValueProcessor valueProcessor;

private final boolean innerJoin;

protected JoinIterator(InstanceCollection instances,
Collection<InstanceReference> startInstances, int[] parent,
Map<PropertyEntityDefinition, Multimap<Object, InstanceReference>> index,
Map<Integer, Multimap<Integer, JoinCondition>> joinTable,
ValueProcessor valueProcessor) {
Map<Integer, Multimap<Integer, JoinCondition>> joinTable, ValueProcessor valueProcessor,
boolean innerJoin) {
super(startInstances.iterator());
this.instances = instances;
this.parent = parent;
this.index = index;
this.joinTable = joinTable;
this.valueProcessor = valueProcessor;
this.innerJoin = innerJoin;

}

/**
* @see eu.esdihumboldt.hale.common.instance.model.impl.GenericResourceIteratorAdapter#convert(java.lang.Object)
*/
@Override
protected FamilyInstance convert(InstanceReference next) {
FamilyInstance base = new FamilyInstanceImpl(instances.getInstance(next));
FamilyInstance[] currentInstances = new FamilyInstance[parent.length];
currentInstances[0] = base;

join(currentInstances, 0);
if (!join(currentInstances, 0)) {
// skip this instance
return null;
}

return base;
}

// Joins all direct children of the given type to currentInstances.
private void join(FamilyInstance[] currentInstances, int currentType) {
/**
* Joins all direct children of the given type to currentInstances.
*
* @return if the instance should be skipped
*/
private boolean join(FamilyInstance[] currentInstances, int currentType) {
// Join all types that are direct children of the last type.
for (int i = currentType + 1; i < parent.length; i++) {
if (parent[i] == currentType) {
Expand Down Expand Up @@ -140,12 +148,22 @@ private void join(FamilyInstance[] currentInstances, int currentType) {
}
parent.addChild(child);
currentInstances[i] = child;
join(currentInstances, i);
if (!join(currentInstances, i)) {
return false;
}
}
currentInstances[i] = null;
}
else {
if (innerJoin) {
// no instances for this link
return false;
}
}
}
}

return true;
}

/**
Expand Down

0 comments on commit c6e943c

Please sign in to comment.