[Mulgara-svn] r804 - in branches/mgr-61-sparql/src/jar: . sparql-interpreter sparql-interpreter/java sparql-interpreter/java/org sparql-interpreter/java/org/mulgara sparql-interpreter/java/org/mulgara/sparql
pag at mulgara.org
pag at mulgara.org
Tue Apr 22 06:26:40 UTC 2008
Author: pag
Date: 2008-04-21 23:26:40 -0700 (Mon, 21 Apr 2008)
New Revision: 804
Added:
branches/mgr-61-sparql/src/jar/sparql-interpreter/
branches/mgr-61-sparql/src/jar/sparql-interpreter/java/
branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/
branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/
branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/
branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/PatternMapper.java
branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java
Log:
Initial commit. This is still a work in progress. There is no conversion of filters yet, and no integration with Ant. A new mapping class is needed in this package, and a new Constraint for setting "IN" values has to go into org.mulgara.query
Added: branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/PatternMapper.java
===================================================================
--- branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/PatternMapper.java (rev 0)
+++ branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/PatternMapper.java 2008-04-22 06:26:40 UTC (rev 804)
@@ -0,0 +1,290 @@
+/**
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+package org.mulgara.sparql;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.mulgara.sparql.parser.cst.BlankNode;
+import org.mulgara.sparql.parser.cst.BooleanLiteral;
+import org.mulgara.sparql.parser.cst.DecimalLiteral;
+import org.mulgara.sparql.parser.cst.DoubleLiteral;
+import org.mulgara.sparql.parser.cst.EmptyGraphPattern;
+import org.mulgara.sparql.parser.cst.Expression;
+import org.mulgara.sparql.parser.cst.GraphPatternConjunction;
+import org.mulgara.sparql.parser.cst.GraphPatternDisjunction;
+import org.mulgara.sparql.parser.cst.GraphPatternOptional;
+import org.mulgara.sparql.parser.cst.GroupGraphPattern;
+import org.mulgara.sparql.parser.cst.IRIReference;
+import org.mulgara.sparql.parser.cst.IntegerLiteral;
+import org.mulgara.sparql.parser.cst.Node;
+import org.mulgara.sparql.parser.cst.RDFLiteral;
+import org.mulgara.sparql.parser.cst.Triple;
+import org.mulgara.sparql.parser.cst.TripleList;
+import org.mulgara.query.ConstraintConjunction;
+import org.mulgara.query.ConstraintDisjunction;
+import org.mulgara.query.ConstraintElement;
+import org.mulgara.query.ConstraintExpression;
+import org.mulgara.query.ConstraintFalse;
+import org.mulgara.query.ConstraintImpl;
+import org.mulgara.query.ConstraintOptionalJoin;
+import org.mulgara.query.Variable;
+import org.mulgara.query.rdf.LiteralImpl;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.query.rdf.XSD;
+
+/**
+ * This object maps a {@link GroupGraphPattern} into a {@link ConstraintExpresion}.
+ *
+ * @created Apr 21, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class PatternMapper {
+
+ /** The pattern to start the mapping on. */
+ GroupGraphPattern startPattern;
+
+ /** An accumulating list of variables that are used in GRAPH patterns. */
+ Set<Variable> graphVars = new HashSet<Variable>();
+
+ /** An accumulating list of URIs that are used in GRAPH patterns. */
+ Set<URI> graphUris = new HashSet<URI>();
+
+ /**
+ * Create a new mapper for a given graph pattern.
+ * @param pattern The graph pattern to be mapped.
+ */
+ PatternMapper(GroupGraphPattern pattern) {
+ startPattern = pattern;
+ initMapping();
+ }
+
+ /**
+ * Get the set of variables that were employed as graphs in GRAPH patterns.
+ * @return The set of variables used in GRAPH expressions.
+ */
+ Set<Variable> getGraphVars() {
+ return graphVars;
+ }
+
+ /**
+ * Perform the mapping of the graph pattern and return the results as a {@link ConstraintExpression}.
+ * @return The mapped constraint expression.
+ */
+ ConstraintExpression mapToConstraints() {
+ return map(startPattern);
+ }
+
+ /**
+ * Converts a pattern to the matching constraint type.
+ * @param pattern The pattern to convert.
+ * @return The new ConstraintExpression which matches the pattern.
+ */
+ private ConstraintExpression map(GroupGraphPattern pattern) {
+ PatternToConstraintMapper<? extends GroupGraphPattern> cons = constructors.get(pattern.getClass());
+ if (cons == null) throw new UnsupportedOperationException("Unknown SPARQL pattern: " + pattern.getClass().getSimpleName());
+ ConstraintExpression result = cons.map(pattern);
+ result = applyFilter(result, pattern.getFilter());
+ result = applyGraph(result, pattern.getGraph());
+ return result;
+ }
+
+ /**
+ * Apply a FILTER to a constraint expression.
+ * @param constraint The expression to be filtered.
+ * @param filter The filter to be wrapped around this constraint.
+ * @return The filtered version of the constraint.
+ */
+ private ConstraintExpression applyFilter(ConstraintExpression constraint, Expression filter) {
+ if (filter == null) return constraint;
+ // TODO create a filter builder and wrap the constraint witha FilteredConstraint
+ return constraint;
+ }
+
+ /**
+ * Apply the parameter of a GRAPH modifier to a constraint expression.
+ * @param constraint The expression to be updated.
+ * @param graph The parameter of the GRAPH expression that is to be propagated through the constraint.
+ * @return The modified version of the constraint.
+ */
+ private ConstraintExpression applyGraph(ConstraintExpression constraint, Expression graph) {
+ if (graph == null) return constraint;
+ // graph is a Variable or IRIReference
+ if (graph instanceof org.mulgara.sparql.parser.cst.Variable) {
+ org.mulgara.sparql.parser.cst.Variable v = (org.mulgara.sparql.parser.cst.Variable)graph;
+ // remember this is variable to be bound to the FROM NAMED values
+ Variable var = new Variable(v.getName());
+ graphVars.add(var);
+ // TODO: wrap the constraint in a new ConstraintIn
+ // constraint = new ConstraintIn(constraint, var);
+ } else if (graph instanceof IRIReference) {
+ // store this reference as a value that should be in the FROM NAMED list
+ URI ref = ((IRIReference)graph).getUri();
+ graphUris.add(ref);
+ // TODO: wrap the constraint in a new ConstraintIn
+ // constraint = new ConstraintIn(constraint, new URIReferenceImpl(ref));
+ } else {
+ throw new IllegalArgumentException("Illegal argument in a GRAPH expression: " + graph.getClass().getSimpleName());
+ }
+ return constraint;
+ }
+
+ /**
+ * A case analysis to convert simple types into {@link ConstraintElement}s.
+ * @param n The {@link Node} to convert to a ConstraintElement.
+ * @return A new constraint element that matches the node n.
+ */
+ private ConstraintElement convertElement(Node n) {
+ if (n instanceof org.mulgara.sparql.parser.cst.Variable) {
+ return new Variable(((org.mulgara.sparql.parser.cst.Variable)n).getName());
+ }
+ if (n instanceof IRIReference) return new URIReferenceImpl(((IRIReference)n).getUri());
+ if (n instanceof BlankNode) return new Variable(((BlankNode)n).getLabel());
+ if (n instanceof RDFLiteral) {
+ RDFLiteral lit = (RDFLiteral)n;
+ if (lit.isTyped()) return new LiteralImpl(lit.getValue(), lit.getDatatype().getUri());
+ if (lit.isLanguageCoded()) return new LiteralImpl(lit.getValue(), lit.getLanguage());
+ return new LiteralImpl(lit.getValue());
+ }
+ // integer, decimal, double, boolean
+ if (n instanceof IntegerLiteral) return new LiteralImpl(((IntegerLiteral)n).getValue().toString(), XSD.INT_URI);
+ if (n instanceof DecimalLiteral) return new LiteralImpl(((IntegerLiteral)n).getValue().toString(), XSD.DECIMAL_URI);
+ if (n instanceof DoubleLiteral) return new LiteralImpl(((IntegerLiteral)n).getValue().toString(), XSD.DOUBLE_URI);
+ if (n instanceof BooleanLiteral) return new LiteralImpl(((IntegerLiteral)n).getValue().toString(), XSD.BOOLEAN_URI);
+ // don't know what to make of this
+ throw new UnsupportedOperationException("Unhandled data type in triple: " + n.getClass().getSimpleName());
+ }
+
+ /**
+ * Converts a Triple from the CST into a ConstraintImpl in the AST.
+ * @param t The triple to convert.
+ * @return The new constraint.
+ */
+ private ConstraintImpl newConstraintImpl(Triple t) {
+ ConstraintElement s = convertElement(t.getSubject());
+ ConstraintElement p = convertElement(t.getPredicate());
+ ConstraintElement o = convertElement(t.getObject());
+ return new ConstraintImpl(s, p, o);
+ }
+
+ /** A mapping of pattern types to constructors for the objects they map to. */
+ private Map<Class<? extends GroupGraphPattern>,PatternToConstraintMapper<? extends GroupGraphPattern>> constructors = new HashMap<Class<? extends GroupGraphPattern>,PatternToConstraintMapper<? extends GroupGraphPattern>>();
+
+ /**
+ * The class for the mapping of {@link GroupGraphPattern}s to {@link ConstraintExpression}s.
+ * This class and extending classes are not static, as the classes will be call back into the
+ * outer class to recurse down the CST.
+ * The reason this is an abstract class instead of an interface is so map(T) can be set
+ * to accept the general GroupGraphPattern and do the cast. This was not possible outside
+ * of the context of the generic type T.
+ */
+ private abstract class PatternToConstraintMapper<T extends GroupGraphPattern> {
+ @SuppressWarnings("unchecked")
+ public ConstraintExpression map(GroupGraphPattern pattern) { return typedMap((T)pattern); }
+ /**
+ * Convert a GroupGraphPattern to a ConstraintExpression for Mulgara.
+ * @param pattern The pattern to convert. Should be specific to the mapper.
+ * @return The constraint expression relevant to the mapper.
+ */
+ abstract ConstraintExpression typedMap(T pattern);
+ /** Identify the class to be mapped by the extension. */
+ public abstract Class<T> getMapType();
+ }
+
+ /**
+ * Utility method to add a pattern mapper to the map, keyed on the class it maps.
+ * @param mapper The mapper to add to the map.
+ */
+ void addToMap(PatternToConstraintMapper<? extends GroupGraphPattern> mapper) {
+ constructors.put(mapper.getMapType(), mapper);
+ }
+
+ /**
+ * Initialize the mapping of patterns to the constraint builders.
+ * This is not static in order to avoid passing "this" through to the methods
+ * on each of the implementing mapper classes.
+ */
+ private void initMapping() {
+ addToMap(new EmptyGraphPatternToConstraint());
+ addToMap(new GraphPatternConjunctionToConstraint());
+ addToMap(new GraphPatternDisjunctionToConstraint());
+ addToMap(new GraphPatternOptionalToConstraint());
+ addToMap(new TripleToConstraint());
+ addToMap(new TripleListToConstraint());
+ }
+
+ /** Map the empty graph pattern to a constraint that always resolves to nothing. */
+ private class EmptyGraphPatternToConstraint extends PatternToConstraintMapper<EmptyGraphPattern> {
+ public Class<EmptyGraphPattern> getMapType() { return EmptyGraphPattern.class; }
+ ConstraintExpression typedMap(EmptyGraphPattern pattern) {
+ return ConstraintFalse.INSTANCE;
+ }
+ }
+
+ /** Map the conjunctions to ConstraintConjunction. */
+ private class GraphPatternConjunctionToConstraint extends PatternToConstraintMapper<GraphPatternConjunction> {
+ public Class<GraphPatternConjunction> getMapType() { return GraphPatternConjunction.class; }
+ ConstraintExpression typedMap(GraphPatternConjunction pattern) {
+ List<GroupGraphPattern> list = pattern.getElements();
+ List<ConstraintExpression> newList = new ArrayList<ConstraintExpression>(list.size());
+ for (GroupGraphPattern p: list) newList.add(map(p));
+ return new ConstraintConjunction(newList);
+ }
+ }
+
+ /** Map the disjunctions to ConstraintConjunction. */
+ private class GraphPatternDisjunctionToConstraint extends PatternToConstraintMapper<GraphPatternDisjunction> {
+ public Class<GraphPatternDisjunction> getMapType() { return GraphPatternDisjunction.class; }
+ ConstraintExpression typedMap(GraphPatternDisjunction pattern) {
+ List<GroupGraphPattern> list = pattern.getElements();
+ List<ConstraintExpression> newList = new ArrayList<ConstraintExpression>(list.size());
+ for (GroupGraphPattern p: list) newList.add(map(p));
+ return new ConstraintDisjunction(newList);
+ }
+ }
+
+ /** Map the optional patterns to ConstraintOptional. */
+ private class GraphPatternOptionalToConstraint extends PatternToConstraintMapper<GraphPatternOptional> {
+ public Class<GraphPatternOptional> getMapType() { return GraphPatternOptional.class; }
+ ConstraintExpression typedMap(GraphPatternOptional pattern) {
+ return new ConstraintOptionalJoin(map(pattern.getMain()), map(pattern.getOptional()));
+ }
+ }
+
+ /** Map the triple patterns to ConstraintImpl. */
+ private class TripleToConstraint extends PatternToConstraintMapper<Triple> {
+ public Class<Triple> getMapType() { return Triple.class; }
+ ConstraintExpression typedMap(Triple pattern) {
+ return newConstraintImpl(pattern);
+ }
+ }
+
+ /** Map the lists of triple patterns to ConstraintConjunctions on ConstraintImpl. */
+ private class TripleListToConstraint extends PatternToConstraintMapper<TripleList> {
+ public Class<TripleList> getMapType() { return TripleList.class; }
+ @SuppressWarnings("unchecked")
+ ConstraintExpression typedMap(TripleList pattern) {
+ List<Triple> triples = (List<Triple>)pattern.getElements();
+ List<ConstraintExpression> constraints = new ArrayList<ConstraintExpression>(triples.size());
+ for (Triple t: triples) constraints.add(newConstraintImpl(t));
+ return new ConstraintConjunction(constraints);
+ }
+ }
+
+}
Added: branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java
===================================================================
--- branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java (rev 0)
+++ branches/mgr-61-sparql/src/jar/sparql-interpreter/java/org/mulgara/sparql/SparqlInterpreter.java 2008-04-22 06:26:40 UTC (rev 804)
@@ -0,0 +1,278 @@
+/**
+ * The contents of this file are subject to the Open Software License
+ * Version 3.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+package org.mulgara.sparql;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.mulgara.parser.Interpreter;
+import org.mulgara.parser.MulgaraLexerException;
+import org.mulgara.parser.MulgaraParserException;
+import org.mulgara.query.ConstraintConjunction;
+import org.mulgara.query.ConstraintDisjunction;
+import org.mulgara.query.ConstraintExpression;
+import org.mulgara.query.ConstraintIs;
+import org.mulgara.query.ModelExpression;
+import org.mulgara.query.ModelResource;
+import org.mulgara.query.ModelUnion;
+import org.mulgara.query.Order;
+import org.mulgara.query.Query;
+import org.mulgara.query.SelectElement;
+import org.mulgara.query.UnconstrainedAnswer;
+import org.mulgara.query.Variable;
+import org.mulgara.query.operation.Command;
+import org.mulgara.query.rdf.URIReferenceImpl;
+import org.mulgara.sparql.parser.ParseException;
+import org.mulgara.sparql.parser.QueryStructure;
+import org.mulgara.sparql.parser.SparqlParser;
+import org.mulgara.sparql.parser.cst.Expression;
+import org.mulgara.sparql.parser.cst.GroupGraphPattern;
+import org.mulgara.sparql.parser.cst.IRIReference;
+import org.mulgara.sparql.parser.cst.Node;
+import org.mulgara.sparql.parser.cst.Ordering;
+
+
+/**
+ * Converts a parsed SPARQL query into a Command for execution.
+ *
+ * @created Apr 18, 2008
+ * @author Paul Gearon
+ * @copyright © 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class SparqlInterpreter implements Interpreter {
+
+ /** The default graph to use if none has been set. */
+ private static final URI INTERNAL_DEFAULT_GRAPH_URI = URI.create("local:null");
+
+ /** The default graph to use when none has been parsed. */
+ private URI defaultGraphUri = null;
+
+ /**
+ * Sets the default graph to use in parsed queries.
+ * @param graph The graph URI to use as the default graph.
+ */
+ public void setDefaultGraphUri(URI graphUri) {
+ defaultGraphUri = graphUri;
+ }
+
+ /**
+ * Gets the default graph to use when none has been parsed from the query.
+ * @return The graph that parsed queries will default to when no FROM graph is supplied.
+ */
+ public URI getDefaultGraphUri() {
+ return (defaultGraphUri != null) ? defaultGraphUri : INTERNAL_DEFAULT_GRAPH_URI;
+ }
+
+ /**
+ * @see org.mulgara.parser.Interpreter#parseCommand(java.lang.String)
+ * The only commands that SPARQL current handles are queries.
+ */
+ public Command parseCommand(String command) throws MulgaraParserException, MulgaraLexerException, IllegalArgumentException, IOException {
+ return parseQuery(command);
+ }
+
+ /**
+ * @see org.mulgara.parser.Interpreter#parseCommands(java.lang.String)
+ * Since SPARQL has no separator character, there can only be one command per string.
+ */
+ public List<Command> parseCommands(String command) throws MulgaraParserException, MulgaraLexerException, IOException, IllegalArgumentException {
+ return Collections.singletonList(parseCommand(command));
+ }
+
+ /**
+ * @see org.mulgara.parser.Interpreter#parseQuery(java.lang.String)
+ */
+ public Query parseQuery(String queryString) throws IOException, MulgaraLexerException, MulgaraParserException {
+ QueryStructure struct;
+ try {
+ struct = SparqlParser.parse(queryString);
+ } catch (ParseException pe) {
+ throw new MulgaraParserException(pe);
+ }
+ switch (struct.getType()) {
+ case select:
+ return buildSelectQuery(struct);
+ case construct:
+ return unhandledType(struct);
+ case describe:
+ return unhandledType(struct);
+ case ask:
+ return unhandledType(struct);
+ default:
+ throw new MulgaraParserException("Unknown query type: " + struct.getType().name());
+ }
+ }
+
+ /**
+ * Respond to an unhandled query type.
+ * @param struct The structure representing the query
+ * @return Nothing. An exception is always thrown.
+ * @throws UnsupportedOperationException An exception explaining that this query type is not handled.
+ */
+ private Query unhandledType(QueryStructure struct) throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("Query type not yet supported: " + struct.getType().name());
+ }
+
+ /**
+ * Converts the elements of a {@link QueryStructure} into a Mulgara {@link Query}.
+ * @param queryStruct The structure to analyze and convert.
+ * @return A new query that can be run as a {@link org.mulgara.query.operation.Command} on a connection.
+ * @throws MulgaraParserException If the query structure contains elements that are not supported by Mulgara.
+ */
+ Query buildSelectQuery(QueryStructure queryStruct) throws MulgaraParserException {
+ List<? extends SelectElement> selection = getSelection(queryStruct);
+ ModelExpression defaultGraphs = getFrom(queryStruct);
+ ConstraintExpression whereClause = getWhere(queryStruct);
+ List<Order> orderBy = getOrdering(queryStruct);
+ Integer limit = getLimit(queryStruct);
+ int offset = queryStruct.getOffset();
+ // null having, unconstrained answer
+ return new Query(selection, defaultGraphs, whereClause, null, orderBy, limit, offset, new UnconstrainedAnswer());
+ }
+
+ /**
+ * Extract the requested variables from this query into a list.
+ * @param queryStruct The query to get the selected variables from.
+ * @return A new list containing Mulgara {@link Variable}s.
+ * @throws MulgaraParserException If and selected elements are not variables.
+ */
+ List<? extends SelectElement> getSelection(QueryStructure queryStruct) throws MulgaraParserException {
+ List<Variable> result = new ArrayList<Variable>();
+ if (queryStruct.isSelectAll()) {
+ Collection<org.mulgara.sparql.parser.cst.Variable> allVars = queryStruct.getAllVariables();
+ for (org.mulgara.sparql.parser.cst.Variable v: allVars) result.add(new Variable(v.getName()));
+ } else {
+ List<? extends Node> selection = queryStruct.getSelection();
+ for (Node n: selection) {
+ // SPARQL only permits variables
+ if (!(n instanceof org.mulgara.sparql.parser.cst.Variable)) throw new MulgaraParserException("Unexpected non-variable in the SELECT clause");
+ org.mulgara.sparql.parser.cst.Variable cv = (org.mulgara.sparql.parser.cst.Variable)n;
+ result.add(new Variable(cv.getName()));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the graph expression ({@link ModelExpression}) the represents the FROM clause, or the default
+ * graph if none was provided.
+ * @param queryStruct The structure to query for the FROM clause.
+ * @return A ModelExpression containing all the required graphs as a union. TODO: this should be a merge.
+ */
+ ModelExpression getFrom(QueryStructure queryStruct) {
+ List<IRIReference> iris = queryStruct.getDefaultFroms();
+ // if there were no named graphs, then use the default
+ if (iris.isEmpty()) return new ModelResource(getDefaultGraphUri());
+ // accumulate the remaining graphs as a union
+ return graphUnion(iris);
+ }
+
+ /**
+ * Convert a list of IRIs into a model resource union of minimal depth. This recurses through construction
+ * of a tree of binary unions, rather than creating a linear linked list of unions.
+ * @param iris The list to convert.
+ * @return A ModelExpression which is a union of all the elements in the list,
+ * or a {@link ModelResource} if the list contains only one element.
+ */
+ private ModelExpression graphUnion(List<IRIReference> iris) {
+ int listSize = iris.size();
+ // terminate on singleton lists
+ if (listSize == 1) return new ModelResource(iris.get(0).getUri());
+ // short circuit for 2 element lists - optimization
+ if (listSize == 2) return new ModelUnion(new ModelResource(iris.get(0).getUri()), new ModelResource(iris.get(1).getUri()));
+ // general case
+ return new ModelUnion(graphUnion(iris.subList(0, listSize / 2)), graphUnion(iris.subList(listSize / 2, listSize)));
+ }
+
+ /**
+ * Creates a list of the ordering to apply to the results. While SPARQL permits ordering by complex
+ * expressions, this is not supported.
+ * @param queryStruct The query structure.
+ * @return A list of {@link Order}, which are each ordered ascending or descending by variable.
+ * @throws MulgaraParserException If the ORDER BY expression was more complex than a simple variable.
+ */
+ List<Order> getOrdering(QueryStructure queryStruct) throws MulgaraParserException {
+ List<Ordering> orderings = queryStruct.getOrderings();
+ List<Order> result = new ArrayList<Order>(orderings.size());
+ for (Ordering order: orderings) {
+ Expression v = order.getExpr();
+ if (!(v instanceof org.mulgara.sparql.parser.cst.Variable)) throw new MulgaraParserException("Unable to support arbitrarily complex ORDER BY clauses.");
+ org.mulgara.sparql.parser.cst.Variable var = (org.mulgara.sparql.parser.cst.Variable)v;
+ result.add(new Order(new Variable(var.getName()), order.isAscending()));
+ }
+ return result;
+ }
+
+ /**
+ * Get the limit described by the query.
+ * @param queryStruct The structure of the query.
+ * @return A {@link java.lang.Integer} containing the limit, or <code>null</code> if there is no limit.
+ */
+ Integer getLimit(QueryStructure queryStruct) {
+ int limit = queryStruct.getLimit();
+ return limit == -1 ? null : limit;
+ }
+
+ /**
+ * Build a WHERE clause for a Mulgara query out of a SPARQL WHERE clause.
+ * @param queryStruct The SPARQL query structure to analyze for the WHERE clause.
+ * @return A Mulgara WHERE clause, as a {@link ConstraintExpression}.
+ */
+ ConstraintExpression getWhere(QueryStructure queryStruct) {
+ // get the basic pattern
+ GroupGraphPattern pattern = queryStruct.getWhereClause();
+ PatternMapper patternMapper = new PatternMapper(pattern);
+ ConstraintExpression result = patternMapper.mapToConstraints();
+ // apply the FROM NAMED expression
+ // TODO: This needs to become a Constraint that wraps LiteralTuples.
+ List<IRIReference> namedFroms = queryStruct.getNamedFroms();
+ if (!namedFroms.isEmpty()) result = addNamedFroms(result, namedFroms, patternMapper.getGraphVars());
+ // possible to ask for non-variables that were employed in GRAPH statements as a parser check.
+ return result;
+ }
+
+ /**
+ * Add in the FROM NAMED values to provide a binding list for each variable used in GRAPH statements.
+ * @param expr The total expression to be modified. This is the WHERE clause.
+ * @param graphs The list of graphs given in the FROM NAMED clauses.
+ * @param graphVars The variables that are used in GRAPH statements.
+ * @return A modified form of expr, with all the graph variables pre-bound.
+ */
+ ConstraintExpression addNamedFroms(ConstraintExpression expr, List<IRIReference> graphs, Set<Variable> graphVars) {
+ List<ConstraintExpression> params = new ArrayList<ConstraintExpression>(graphVars.size() + 1);
+ params.add(expr);
+ for (Variable var: graphVars) params.add(newListConstraint(var, graphs));
+ return new ConstraintConjunction(params);
+ }
+
+ /**
+ * Construct a constraint expression that binds a variable to a list of values.
+ * TODO: This needs to be represented by a new Constraint that gets converted to a LiteralTuples.
+ * @param var The variable to bind.
+ * @param bindingList The list of values to bind the variable to.
+ * @return A new {@link org.mulgara.query.Constraint} that represents the variable binding.
+ */
+ ConstraintExpression newListConstraint(Variable var, List<IRIReference> bindingList) {
+ List<ConstraintExpression> isConstraints = new ArrayList<ConstraintExpression>(bindingList.size());
+ for (IRIReference iri: bindingList) {
+ // does this need a graph node that isn't variable?
+ isConstraints.add(new ConstraintIs(var, new URIReferenceImpl(iri.getUri())));
+ }
+ return new ConstraintDisjunction(isConstraints);
+ }
+}
More information about the Mulgara-svn
mailing list