Skip to content

Commit

Permalink
GH-4066 refactor ProjectionElem to clarify use of targetName
Browse files Browse the repository at this point in the history
This makes it clearer why this mechanism exists in addition to Extension
elements.
  • Loading branch information
abrokenjester committed Aug 27, 2022
1 parent e75aab5 commit c607df2
Show file tree
Hide file tree
Showing 23 changed files with 299 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
Expand Down Expand Up @@ -271,8 +270,8 @@ public void meet(Var node) throws QueryEvaluationException {
@Override
public void meet(ProjectionElem node) throws QueryEvaluationException {
super.meet(node);
node.setSourceName(varNames.computeIfAbsent(node.getSourceName(), k -> k));
node.setTargetName(varNames.computeIfAbsent(node.getTargetName(), k -> k));
node.setName(varNames.computeIfAbsent(node.getName(), k -> k));
node.setProjectionAlias(varNames.computeIfAbsent(node.getProjectionAlias().orElse(null), k -> k));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void optimize(TupleExpr tupleExpr, Dataset dataset, BindingSet bindings)
varsBefore.removeAll(varsAfter);
for (ProjectionElemList projElems : visitor.projElemLists) {
for (ProjectionElem projElem : projElems.getElements()) {
String name = projElem.getSourceName();
String name = projElem.getName();
if (varsBefore.contains(name)) {
UnaryTupleOperator proj = (UnaryTupleOperator) projElems.getParentNode();
Extension ext = new Extension(proj.getArg());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,7 @@ public void meet(Var node) {
if (projection != null) {
boolean projected = false;
for (ProjectionElem e : projection.getProjectionElemList().getElements()) {
String source = e.getSourceName();
String target = e.getTargetName();
if (node.getName().equals(source) && node.getName().equals(target)) {
if (node.getName().equals(e.getName())) {
projected = true;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ public void meet(Var var) {

@Override
public void meet(ProjectionElem projElem) throws RuntimeException {
if (projElem.getSourceName().equals(oldVar.getName())) {
projElem.setSourceName(newVar.getName());
if (projElem.getName().equals(oldVar.getName())) {
projElem.setName(newVar.getName());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ public ProjectionIterator(Projection projection, CloseableIteration<BindingSet,

BiConsumer<MutableBindingSet, BindingSet> consumer = null;
for (ProjectionElem pe : projectionElemList.getElements()) {
String sourceName = pe.getSourceName();
String targetName = pe.getTargetName();
Function<BindingSet, Value> valueWithSourceName = context.getValue(sourceName);
BiConsumer<Value, MutableBindingSet> setTarget = context.setBinding(targetName);
String projectionName = pe.getProjectionAlias().orElse(pe.getName());
Function<BindingSet, Value> valueWithSourceName = context.getValue(pe.getName());
BiConsumer<Value, MutableBindingSet> setTarget = context.setBinding(projectionName);
BiConsumer<MutableBindingSet, BindingSet> next = (resultBindings, sourceBindings) -> {
Value targetValue = valueWithSourceName.apply(sourceBindings);
if (!includeAllParentBindings && targetValue == null) {
Expand Down Expand Up @@ -120,12 +119,12 @@ public static BindingSet project(ProjectionElemList projElemList, BindingSet sou
final QueryBindingSet resultBindings = makeNewQueryBindings(parentBindings, includeAllParentBindings);

for (ProjectionElem pe : projElemList.getElements()) {
Value targetValue = sourceBindings.getValue(pe.getSourceName());
Value targetValue = sourceBindings.getValue(pe.getName());
if (!includeAllParentBindings && targetValue == null) {
targetValue = parentBindings.getValue(pe.getSourceName());
targetValue = parentBindings.getValue(pe.getName());
}
if (targetValue != null) {
resultBindings.setBinding(pe.getTargetName(), targetValue);
resultBindings.setBinding(pe.getProjectionAlias().orElse(pe.getName()), targetValue);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public void optimize(TupleExpr tupleExpr, Dataset dataset, BindingSet bindings)
for (ProjectionElemList projElems : visitor.projElemLists) {
for (ProjectionElem projElem : projElems.getElements()) {

String name = projElem.getSourceName();
String name = projElem.getName();

if (varsBefore.contains(name)) {
UnaryTupleOperator proj = (UnaryTupleOperator) projElems.getParentNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ public void meet(Var node) {
if (projection != null) {
boolean projected = false;
for (ProjectionElem e : projection.getProjectionElemList().getElements()) {
String source = e.getSourceName();
String target = e.getTargetName();
if (node.getName().equals(source) && node.getName().equals(target)) {
if (node.getName().equals(e.getName())) {
projected = true;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ public void meet(Var var) {

@Override
public void meet(ProjectionElem projElem) throws RuntimeException {
if (projElem.getSourceName().equals(oldVar.getName())) {
projElem.setSourceName(newVar.getName());
if (projElem.getName().equals(oldVar.getName())) {
projElem.setName(newVar.getName());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public Set<String> getBindingNames() {
Set<String> bindingNames = new HashSet<>();

for (ProjectionElemList projElemList : projections) {
bindingNames.addAll(projElemList.getTargetNames());
bindingNames.addAll(projElemList.getProjectedNames());
}

return bindingNames;
Expand All @@ -89,10 +89,10 @@ public Set<String> getAssuredBindingNames() {
if (projections.size() >= 1) {
Set<String> assuredSourceNames = getArg().getAssuredBindingNames();

bindingNames.addAll(projections.get(0).getTargetNamesFor(assuredSourceNames));
bindingNames.addAll(projections.get(0).getProjectedNamesFor(assuredSourceNames));

for (int i = 1; i < projections.size(); i++) {
bindingNames.retainAll(projections.get(i).getTargetNamesFor(assuredSourceNames));
bindingNames.retainAll(projections.get(i).getProjectedNamesFor(assuredSourceNames));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ public void setProjectionElemList(ProjectionElemList projElemList) {

@Override
public Set<String> getBindingNames() {
return projElemList.getTargetNames();
return projElemList.getProjectedNames();
}

@Override
public Set<String> getAssuredBindingNames() {
// Return all target binding names for which the source binding is assured
// by the argument
return projElemList.getTargetNamesFor(getArg().getAssuredBindingNames());
return projElemList.getProjectedNamesFor(getArg().getAssuredBindingNames());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,56 +10,135 @@
*******************************************************************************/
package org.eclipse.rdf4j.query.algebra;

import java.util.Objects;
import java.util.Optional;

/**
* Projection elements control which of the selected expressions (produced by the WHERE clause of a query) are returned
* in the solution, and the order in which they appear.
* <p>
* In SPARQL SELECT queries, projection elements are the variables determined by the algorithm for finding SELECT
* expressions (see <a href="https://www.w3.org/TR/sparql11-query/#sparqlSelectExpressions">SPARQL 1.1 Query Language
* Recommendation, section 18.2.4.4</a>). Each projection element will be a single variable name (any aliasing is
* handled by the use of {@link Extension}s).
* <p>
* In SPARQL CONSTRUCT queries, the projection elements are used to map the variables obtained from the SELECT
* expressions to the required statement patterns. In this case, each projection element will have an additional
* {@link #getProjectionAlias() target name} that maps each projection variable name to one of {@code subject},
* {@code predicate}, {@code object} or {@code context}.
*
* @author Jeen Broekstra
*/
public class ProjectionElem extends AbstractQueryModelNode {

/*-----------*
* Variables *
*-----------*/
private static final long serialVersionUID = -8129811335486478066L;

private String sourceName;
private String name;

private String targetName;
private String projectionAlias;

private boolean aggregateOperatorInExpression;

private ExtensionElem sourceExpression;

/*--------------*
* Constructors *
*--------------*/

/**
* Create a new empty {@link ProjectionElem}.
*/
public ProjectionElem() {
}

/**
* Create a new {@link ProjectionElem} with a variable name.
*
* @param name The name of the projection element (typically the name of the variable in the select expressions).
* May not be <code>null</code>.
*/
public ProjectionElem(String name) {
this(name, name);
this(name, null);
}

public ProjectionElem(String sourceName, String targetName) {
setSourceName(sourceName);
setTargetName(targetName);
/**
* Create a new {@link ProjectionElem} with a variable name and an additional mapped {@link #getProjectionAlias()
* target name}
*
* @param name The name of the projection element (typically the name of the variable in the select
* expressions). May not be <code>null</code>.
* @param targetName The name of the variable the projection element value should be mapped to, to produce the
* projection. Used in CONSTRUCT queries for mapping select expressions to statement patterns. May
* be <code>null</code>.
*/
public ProjectionElem(String name, String targetName) {
setName(name);
setProjectionAlias(targetName);
}

/*---------*
* Methods *
*---------*/
/**
* Get the name of the projection element (typically the name of the variable in the select expressions)
*
*/
public String getName() {
return name;
}

/**
* @deprecated since 4.1.1. Use {@link #getName()} instead.
*/
@Deprecated(since = "4.1.1", forRemoval = true)
public String getSourceName() {
return sourceName;
return getName();
}

/**
* @deprecated since 4.1.1. Use {@link #setName(String)} instead.
*/
@Deprecated(since = "4.1.1", forRemoval = true)
public void setSourceName(String sourceName) {
assert sourceName != null : "sourceName must not be null";
this.sourceName = sourceName;
setName(sourceName);
}

public String getTargetName() {
return targetName;
/**
* Set the name of the projection element (typically the name of the variable in the select expressions)
*
* @param name the projection variable name. May not be {@code null}.
*/
public void setName(String name) {
this.name = Objects.requireNonNull(name);
}

/**
* Get the alias the projection element value should be mapped to. Used in CONSTRUCT queries for mapping select
* expressions to statement patterns.
*
* @return an optionally empty projection alias.
*/
public Optional<String> getProjectionAlias() {
return Optional.ofNullable(projectionAlias);
}

/**
* Set the alias the projection element value should be mapped to. Used in CONSTRUCT queries for mapping select
* expressions to statement patterns.
*
* @param alias the projection alias.
*/
public void setProjectionAlias(String alias) {
this.projectionAlias = alias;
}

/**
* @deprecated since 4.1.1. Use {@link #setProjectionAlias(String)} instead.
*/
@Deprecated(since = "4.1.1", forRemoval = true)
public void setTargetName(String targetName) {
assert targetName != null : "targetName must not be null";
this.targetName = targetName;
setProjectionAlias(targetName);
}

/**
* @deprecated since 4.1.1. Use {@link #getProjectionAlias()} instead.
*/
@Deprecated(since = "4.1.1", forRemoval = true)
public String getTargetName() {
return getProjectionAlias().orElse(null);
}

@Override
Expand All @@ -78,11 +157,11 @@ public String getSignature() {
sb.append(super.getSignature());

sb.append(" \"");
sb.append(sourceName);
sb.append(name);
sb.append("\"");

if (!sourceName.equals(targetName)) {
sb.append(" AS \"").append(targetName).append("\"");
if (projectionAlias != null) {
sb.append(" AS \"").append(projectionAlias).append("\"");
}

return sb.toString();
Expand All @@ -92,15 +171,14 @@ public String getSignature() {
public boolean equals(Object other) {
if (other instanceof ProjectionElem) {
ProjectionElem o = (ProjectionElem) other;
return sourceName.equals(o.getSourceName()) && targetName.equals(o.getTargetName());
return name.equals(o.getName()) && Objects.equals(getProjectionAlias(), o.getProjectionAlias());
}
return false;
}

@Override
public int hashCode() {
// Note: don't xor source and target since they will often be equal
return targetName.hashCode();
return Objects.hash(name, projectionAlias);
}

@Override
Expand Down
Loading

0 comments on commit c607df2

Please sign in to comment.