All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.weaverplatform.sp4rql.model.solution.Sp4rqlSolution Maven / Gradle / Ivy

package com.weaverplatform.sp4rql.model.solution;

import com.weaverplatform.sp4rql.error.ParseException;
import com.weaverplatform.sp4rql.model.expression.ExpressionArgument;
import com.weaverplatform.sp4rql.model.expression.ExpressionUnit;
import com.weaverplatform.sp4rql.model.expression.OperatorType;
import com.weaverplatform.sp4rql.model.restriction.*;
import com.weaverplatform.sp4rql.model.scope.ScopeSimple;
import com.weaverplatform.sp4rql.model.scope.Sp4rqlScope;
import com.weaverplatform.sp4rql.model.token.*;
import com.weaverplatform.util.IndentStringBuilder;

import java.util.HashSet;

/*
 * A solution is a set of elements that needs to be resolved during query execution.
 * Typically the solution will be bound to a ?variable in the result set. But also
 * non returned solution are used.
 *
 * The type of elements inside the selection can be derived from the query.
 */
public class Sp4rqlSolution {

  protected VariableToken binding;
  protected ExpressionUnit aggregationExpression = null;
  protected HashSet restrictions = new HashSet<>();
  protected final SolutionType type = new SolutionType();
  protected HashSet equalSolutions = new HashSet<>();
  protected Sp4rqlScope scope;

  public Sp4rqlSolution(VariableToken token) {
    binding = token;
  }

  public void setScope(Sp4rqlScope scope) {
    this.scope = scope;
  }

  private void addEqualSolution(Sp4rqlSolution other) {
    this.equalSolutions.add(other);
    other.equalSolutions.add(this);
  }

  public void addRestriction(Sp4rqlRestriction restriction) {
    restrictions.add(restriction);
  }

  public void setAggregationExpression(ExpressionUnit expression) {
    this.aggregationExpression = expression;
  }

  public VariableToken getBinding() {
    return binding;
  }

  public HashSet getRestrictions() {
    return restrictions;
  }

  public void analyseTypes() {
    if(aggregationExpression != null) {
      analyseTypes(aggregationExpression);
    } else {
      for (Sp4rqlRestriction restriction : getRestrictions()) {
        if (restriction instanceof BindRestriction) {
          analyseTypes((BindRestriction) restriction);
        } else if (restriction instanceof FilterRestriction) {
          // a filter restriction does not expose anything to a binding (todo: also check on type of input variables)
        } else if (restriction instanceof SingleTermRestriction) {
          analyseTypes((SingleTermRestriction) restriction);
        } else if (restriction instanceof QuadRestriction) {
          analyseTypes((QuadRestriction) restriction);
        } else if (restriction instanceof ValuesRestriction) {
          analyseTypes((ValuesRestriction) restriction);
        } else if (restriction instanceof Sp4rqlScope) {
          // no need to inspect scopes
        } else {
          throw new ParseException("Unsupported restriction type to analyse");
        }
      }
    }
  }

  private void analyseTypes(ExpressionUnit expression) {
    type.mustBeOneOf(OperatorType.getType(expression.getOperator()));
  }

  private void analyseTypes(BindRestriction restriction) {
    ExpressionArgument expression = restriction.getExpression();
    if(expression instanceof VariableToken) {
      Sp4rqlSolution other = scope.getSolution((VariableToken) expression);
      addEqualSolution(other); // todo: do the same for FILTER ?x = ?y
    } else if(expression instanceof ReferenceToken) {
      type.mustBeOneOf(SolutionType.NODE, SolutionType.GRAPH, SolutionType.PREDICATE);
    } else if(expression instanceof LiteralToken) {
      type.mustBeOneOf(SolutionType.LITERAL);
    } else if(expression instanceof ExpressionUnit) {
      Integer resolvesTo = expression.resolvesTo();
      type.mustBeOneOf(resolvesTo);
    } else {
      throw new ParseException("Do not ask resolvesTo of this restriction type when analysing types");
    }
  }

  private void analyseTypes(SingleTermRestriction restriction) {
    if(restriction.inScope() instanceof ScopeSimple) {
      Sp4rqlToken graphSelector = ((ScopeSimple) restriction.inScope()).getGraphSelector();
      if(binding.equals(graphSelector)) {
        type.mustBeOneOf(SolutionType.GRAPH);
      }
    }
    if (binding.equals(restriction.getVariable())) {
      type.mustBeOneOf(SolutionType.NODE);
    }
  }

  private void analyseTypes(QuadRestriction restriction) {
    if(restriction.inScope() instanceof ScopeSimple) {
      Sp4rqlToken graphSelector = ((ScopeSimple) restriction.inScope()).getGraphSelector();
      if(binding.equals(graphSelector)) {
        type.mustBeOneOf(SolutionType.GRAPH);
      }
    }
    if (binding.equals(restriction.getStatement())) {
      if (restriction.getObject() instanceof LiteralToken) {
        type.mustBeOneOf(SolutionType.LITERAL_STATEMENT);
      } else if (restriction.getObject() instanceof ReferenceToken) {
        type.mustBeOneOf(SolutionType.NODE_STATEMENT);
      } else {
        type.mustBeOneOf(SolutionType.NODE_STATEMENT, SolutionType.LITERAL_STATEMENT);
      }
    }
    if (binding.equals(restriction.getSubject())) {
      type.mustBeOneOf(SolutionType.NODE);
    }
    if (binding.equals(restriction.getPredicate())) {
      type.mustBeOneOf(SolutionType.PREDICATE);
    }
    if (binding.equals(restriction.getObject())) {
      type.mustBeOneOf(SolutionType.NODE, SolutionType.LITERAL);
    }
  }

  private void analyseTypes(ValuesRestriction restriction) {
    boolean literal = false;
    boolean node = false;
    if(binding instanceof VariableToken && restriction.getExposedVariables().contains(binding)) {
      for(Sp4rqlToken value : restriction.getValues((VariableToken) binding)) {
        literal |= (value instanceof LiteralToken);
        node |= (value instanceof ReferenceToken);
      }
    }
    if(literal && !node) {
      type.mustBeOneOf(SolutionType.LITERAL);
    } else if(!literal && node) {
      type.mustBeOneOf(SolutionType.NODE, SolutionType.PREDICATE, SolutionType.GRAPH);
    } else {
      type.mustBeOneOf(SolutionType.LITERAL, SolutionType.NODE, SolutionType.PREDICATE, SolutionType.GRAPH);
    }
  }

  public SolutionType getSolutionType() {
    return type;
  }

  public void tuneEqualSolutions() {
    for(Sp4rqlSolution other : equalSolutions) {
      type.supplement(other.getSolutionType());
      other.getSolutionType().supplement(this.type);
    }
  }

  public HashSet getEqualTokens() {
    HashSet set = new HashSet<>();
    for(Sp4rqlSolution other : equalSolutions) {
      set.add(other.getBinding());
    }
    return set;
  }

  @Override
  public String toString() {
    IndentStringBuilder builder = new IndentStringBuilder();
    builder.appendLine(String.format("Type: %s", type));
    builder.appendLine(String.format("Binding: %s", binding.toString()));
    builder.appendLine("Restrictions:");
    for(Sp4rqlRestriction restriction : restrictions) {
      builder.appendLine(restriction.getAlias());
    }
    return builder.toString();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy