LeftJoinIteratorTest.java
/*******************************************************************************
* Copyright (c) 2025 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.query.algebra.evaluation.iterator;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.model.*;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.algebra.*;
import org.eclipse.rdf4j.query.algebra.evaluation.*;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.DefaultEvaluationStrategy;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class LeftJoinIteratorTest {
private static final QueryBindingSet RIGHT_BINDINGS = new QueryBindingSet(1);
private static final ValueFactory VALUE_FACTORY = SimpleValueFactory.getInstance();
private static final EvaluationStrategy EVALUATOR = new DefaultEvaluationStrategy(new TripleSource() {
@Override
public ValueFactory getValueFactory() {
return SimpleValueFactory.getInstance();
}
@Override
public CloseableIteration<? extends Statement> getStatements(Resource subj, IRI pred,
Value obj, Resource... contexts) throws QueryEvaluationException {
return null;
}
}, null);
private QueryBindingSet bindingSet;
private BindingSetAssignment left;
private QueryEvaluationStep leftHandSide;
private RightHandSideQueryEvaluationStep rightHandSide;
@BeforeAll
static void beforeAll() {
RIGHT_BINDINGS.addBinding("right", VALUE_FACTORY.createLiteral(42));
}
@BeforeEach
void setUp() {
bindingSet = new QueryBindingSet(1);
bindingSet.addBinding("left", VALUE_FACTORY.createLiteral(42));
left = new BindingSetAssignment();
left.setBindingSets(List.of(bindingSet));
leftHandSide = EVALUATOR.precompile(left);
rightHandSide = new RightHandSideQueryEvaluationStep();
}
@Test
void evaluatesRightHandSideQueryEvaluationStep() {
try (LeftJoinIterator iterator = new LeftJoinIterator(leftHandSide.evaluate(bindingSet), rightHandSide)) {
iterator.getNextElement();
}
assertTrue(rightHandSide.isEvaluated);
}
private static class RightHandSideQueryEvaluationStep implements QueryEvaluationStep {
private boolean isEvaluated = false;
@Override
public CloseableIteration<BindingSet> evaluate(BindingSet bindings) {
isEvaluated = true;
var bothBindings = new QueryBindingSet(2);
bindings.forEach(bothBindings::addBinding);
RIGHT_BINDINGS.forEach(bothBindings::addBinding);
var rightIterator = List.of(bothBindings).iterator();
return new CloseableIteration<>() {
@Override
public void close() {
// Nothing to close
}
@Override
public boolean hasNext() {
return rightIterator.hasNext();
}
@Override
public BindingSet next() {
return rightIterator.next();
}
};
}
}
}