QueryEvaluationStep.java

/*******************************************************************************
 * Copyright (c) 2021 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;

import java.util.function.Function;

import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.common.iteration.DelayedIteration;
import org.eclipse.rdf4j.common.iteration.EmptyIteration;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.algebra.TupleExpr;

/**
 * A Step that may need to be executed in a EvaluationStrategy. The evaluate method should do the minimal work required
 * to evaluate given the bindings. As much as possible should be pre-computed (e.g. resolving constant values)
 */
@FunctionalInterface
public interface QueryEvaluationStep {

	EmptyIteration<BindingSet> EMPTY_ITERATION = new EmptyIteration<>();
	QueryEvaluationStep EMPTY = bindings -> EMPTY_ITERATION;

	/**
	 * Utility class that removes code duplication and makes a precompiled QueryEvaluationStep available as an iteration
	 * that may be created and used later.
	 */
	class DelayedEvaluationIteration extends DelayedIteration<BindingSet> {
		private final QueryEvaluationStep arg;
		private final BindingSet bs;

		public DelayedEvaluationIteration(QueryEvaluationStep arg, BindingSet bs) {
			this.arg = arg;
			this.bs = bs;
		}

		@Override
		protected CloseableIteration<? extends BindingSet> createIteration()
				throws QueryEvaluationException {
			return arg.evaluate(bs);
		}
	}

	CloseableIteration<BindingSet> evaluate(BindingSet bindings);

	/**
	 * A fall back implementation that wraps a pre-existing evaluate method on a strategy
	 *
	 * @param strategy that can evaluate the tuple expr.
	 * @param expr     that is going to be evaluated
	 * @return a thin wrapper arround the evaluation call.
	 */
	static QueryEvaluationStep minimal(EvaluationStrategy strategy, TupleExpr expr) {
		return bs -> strategy.evaluate(expr, bs);
	}

	static QueryEvaluationStep empty() {
		return EMPTY;
	}

	/**
	 * Wrap an QueryEvalationStep: where we apply a function on every evaluation result of the wrapped EvaluationStep.
	 * Useful to add a timing function
	 *
	 * @param qes  an QueryEvaluationStep that needs to return modified evaluation results
	 * @param wrap the function that will do the modification
	 * @return a new evaluation step that executes wrap on the inner qes.
	 */
	static QueryEvaluationStep wrap(QueryEvaluationStep qes,
			Function<CloseableIteration<BindingSet>, CloseableIteration<BindingSet>> wrap) {
		return bs -> wrap.apply(qes.evaluate(bs));
	}
}