You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by cl...@apache.org on 2017/06/04 11:39:23 UTC

[2/6] jena git commit: Initial implementation with tests

Initial implementation with tests

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/7d96286e
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/7d96286e
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/7d96286e

Branch: refs/heads/master
Commit: 7d96286e1b49dc170604dd76f81abfc3f397541a
Parents: a2fb93c
Author: Claude Warren <cl...@apache.org>
Authored: Sun Jun 4 12:07:56 2017 +0100
Committer: Claude Warren <cl...@apache.org>
Committed: Sun Jun 4 12:07:56 2017 +0100

----------------------------------------------------------------------
 .../arq/querybuilder/AbstractQueryBuilder.java  |    5 +
 .../jena/arq/querybuilder/UpdateBuilder.java    | 1027 ++++++++++++++++++
 .../arq/querybuilder/handlers/WhereHandler.java |   23 +-
 .../updatebuilder/PrefixHandler.java            |  115 ++
 .../updatebuilder/QBQuadHolder.java             |   79 ++
 .../querybuilder/updatebuilder/QuadHolder.java  |   46 +
 .../updatebuilder/QuadIteratorBuilder.java      |  180 +++
 .../updatebuilder/SingleQuadHolder.java         |   97 ++
 .../updatebuilder/WhereProcessor.java           |  433 ++++++++
 .../src/test/java/Example10.java                |  104 ++
 .../querybuilder/UpdateBuilderExampleTests.java |  659 +++++++++++
 .../arq/querybuilder/UpdateBuilderTest.java     |  411 +++++++
 12 files changed, 3175 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
index ed18272..17be323 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/AbstractQueryBuilder.java
@@ -50,6 +50,7 @@ import org.apache.jena.sparql.path.P_Link;
 import org.apache.jena.sparql.path.Path;
 import org.apache.jena.sparql.path.PathParser;
 import org.apache.jena.sparql.syntax.ElementGroup;
+import org.apache.jena.sparql.syntax.ElementSubQuery;
 import org.apache.jena.sparql.util.ExprUtils;
 import org.apache.jena.sparql.util.NodeFactoryExtra ;
 
@@ -132,6 +133,10 @@ public abstract class AbstractQueryBuilder<T extends AbstractQueryBuilder<T>>
 		return NodeFactory.createLiteral(LiteralLabelFactory.createTypedLiteral(o));
 	}
 		
+	public ElementSubQuery asSubQuery() {
+		return getWhereHandler().makeSubQuery( this );
+	}
+	
 	/**
 	 * Make a triple path from the objects.
 	 * 

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java
new file mode 100644
index 0000000..93aeae6
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/UpdateBuilder.java
@@ -0,0 +1,1027 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.arq.querybuilder;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import org.apache.jena.arq.querybuilder.clauses.PrologClause;
+import org.apache.jena.arq.querybuilder.clauses.WhereClause;
+import org.apache.jena.arq.querybuilder.handlers.WhereHandler;
+import org.apache.jena.arq.querybuilder.updatebuilder.PrefixHandler;
+import org.apache.jena.arq.querybuilder.updatebuilder.QBQuadHolder;
+import org.apache.jena.arq.querybuilder.updatebuilder.QuadHolder;
+import org.apache.jena.arq.querybuilder.updatebuilder.SingleQuadHolder;
+import org.apache.jena.arq.querybuilder.updatebuilder.WhereProcessor;
+import org.apache.jena.graph.FrontsTriple;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.query.QueryParseException;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.shared.PrefixMapping;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.core.TriplePath;
+import org.apache.jena.sparql.core.Var;
+import org.apache.jena.sparql.expr.Expr;
+import org.apache.jena.sparql.lang.sparql_11.ParseException;
+import org.apache.jena.sparql.modify.request.QuadAcc;
+import org.apache.jena.sparql.modify.request.QuadDataAcc;
+import org.apache.jena.sparql.modify.request.UpdateDataDelete;
+import org.apache.jena.sparql.modify.request.UpdateDataInsert;
+import org.apache.jena.sparql.modify.request.UpdateDeleteWhere;
+import org.apache.jena.sparql.modify.request.UpdateModify;
+import org.apache.jena.update.Update;
+import org.apache.jena.update.UpdateRequest;
+import org.apache.jena.util.iterator.ExtendedIterator;
+import org.apache.jena.util.iterator.NiceIterator;
+import org.apache.jena.vocabulary.RDF;
+
+/**
+ * Class to build update requests.
+ *
+ */
+public class UpdateBuilder {
+
+	private final PrefixHandler prefixHandler;
+	private final WhereProcessor whereProcessor;
+	private List<QuadHolder> inserts = new ArrayList<QuadHolder>();
+	private List<QuadHolder> deletes = new ArrayList<QuadHolder>();
+	private Map<Var, Node> values;
+	private Node with;
+
+	/**
+	 * Constructor.
+	 */
+	public UpdateBuilder() {
+		this.prefixHandler = new PrefixHandler();
+		this.whereProcessor = new WhereProcessor(prefixHandler);
+		this.values = new HashMap<Var, Node>();
+		this.with = null;
+	}
+
+	/**
+	 * Constructor. Uses the prefixes from the prolog clause. <b>May modify the
+	 * contents of the prefix mapping in the prolog handler</b>
+	 * 
+	 * @param prologClause
+	 *            the default prefixes for this builder.
+	 */
+	public UpdateBuilder(PrologClause<?> prologClause) {
+		this(prologClause.getPrologHandler().getPrefixes());
+	}
+
+	/**
+	 * Constructor. Uses the specified prefix mapping. <b>May modify the
+	 * contents of the prefix mapping</b>
+	 * 
+	 * @param pMap
+	 *            the prefix mapping to use.
+	 */
+	public UpdateBuilder(PrefixMapping pMap) {
+		this.prefixHandler = new PrefixHandler(pMap);
+		this.whereProcessor = new WhereProcessor(prefixHandler);
+	}
+
+	// conver a collection of QuadHolder to an iterator on quads.
+	private ExtendedIterator<Quad> getQuads(Collection<QuadHolder> holders) {
+		ExtendedIterator<Quad> result = NiceIterator.emptyIterator();
+		for (QuadHolder holder : holders) {
+			result = result.andThen(holder.setValues(values).getQuads());
+		}
+		return result;
+	}
+
+	/**
+	 * Build the update.
+	 * 
+	 * <b>Note: the update does not include the prefix statements</b> use
+	 * buildRequest() or appendTo() methods to include the prefix statements.
+	 * 
+	 * @return the update.
+	 */
+	public Update build() {
+
+		if (deletes.isEmpty() && inserts.isEmpty()) {
+			throw new IllegalStateException("At least one delete or insert must be specified");
+		}
+
+		if (whereProcessor.isEmpty()) {
+			return buildNoWhere();
+		}
+		return buildWhere();
+	}
+
+	/**
+	 * Build as an UpdateRequest with prefix mapping set.
+	 * 
+	 * @return a new UpdateRequest
+	 */
+	public UpdateRequest buildRequest() {
+		UpdateRequest req = new UpdateRequest(build());
+		req.setPrefixMapping(prefixHandler.getPrefixes());
+		return req;
+	}
+
+	/**
+	 * Appends the new Update to the UpdateRequest.
+	 * 
+	 * @param req
+	 *            the UpdateRequest to append this Update to.
+	 * @return the req parameter for chaining.
+	 */
+	public UpdateRequest appendTo(UpdateRequest req) {
+		req.add(build());
+		for (Map.Entry<String, String> entry : prefixHandler.getPrefixes().getNsPrefixMap().entrySet()) {
+			req.setPrefix(entry.getKey(), entry.getValue());
+		}
+		return req;
+	}
+
+	// build updates without where clauses
+	private Update buildNoWhere() {
+		if (inserts.isEmpty()) {
+			QuadDataAcc quadData = new QuadDataAcc(getQuads(deletes).mapWith(new Function<Quad, Quad>() {
+				@Override
+				public Quad apply(Quad arg0) {
+					return check(arg0);
+				}
+			}).toList());
+			return new UpdateDataDelete(quadData);
+		}
+		if (deletes.isEmpty()) {
+			QuadDataAcc quadData = new QuadDataAcc(getQuads(inserts).mapWith(new Function<Quad, Quad>() {
+
+				@Override
+				public Quad apply(Quad t) {
+					return check(t);
+				}
+
+			}).toList());
+			return new UpdateDataInsert(quadData);
+		}
+
+		throw new IllegalStateException("Can not have both insert and delete without a where clause");
+	}
+
+	// build updates with where clauses
+	private Update buildWhere() {
+
+		// if (inserts.isEmpty()) {
+		// QuadAcc quadAcc = new QuadAcc(getQuads(deletes).toList());
+		// UpdateDeleteWhere retval = new UpdateDeleteWhere(quadAcc);
+		// return retval;
+		// }
+
+		UpdateModify retval = new UpdateModify();
+		if (with != null)
+		{
+			Node graph = values.get(with);
+			if (graph == null) {
+				graph = with;
+			}
+			retval.setWithIRI(graph);
+		}
+		QuadAcc acc;
+		Iterator<Quad> iter;
+
+		if (!inserts.isEmpty()) {
+			retval.setHasInsertClause(true);
+			acc = retval.getInsertAcc();
+			iter = getQuads(inserts);
+			while (iter.hasNext()) {
+				acc.addQuad(iter.next());
+			}
+		}
+		if (!deletes.isEmpty()) {
+			retval.setHasDeleteClause(true);
+			acc = retval.getDeleteAcc();
+
+			iter = getQuads(deletes);
+			while (iter.hasNext()) {
+				acc.addQuad(iter.next());
+			}
+		}
+		
+		retval.setElement(whereProcessor.setVars(values));
+		
+		return retval;
+
+	}
+
+	/**
+	 * Convert the object to a node.
+	 * 
+	 * Shorthand for AbstractQueryBuilder.makeNode( o, prefixes )
+	 * 
+	 * @see AbstractQueryBuilder#makeNode(Object)
+	 * 
+	 * @param o
+	 *            the object to convert to a node.
+	 * @return the Node.
+	 */
+	public Node makeNode(Object o) {
+		return AbstractQueryBuilder.makeNode(o, prefixHandler.getPrefixes());
+	}
+
+	/**
+	 * Convert the object to a node.
+	 * 
+	 * Shorthand for AbstractQueryBuilder.makeVar( o )
+	 * 
+	 * @see AbstractQueryBuilder#makeVar(Object)
+	 * 
+	 * @param o
+	 *            the object to convert to a var.
+	 * @return the Var.
+	 */
+
+	public Var makeVar(Object o) {
+		return AbstractQueryBuilder.makeVar(o);
+	}
+
+	/**
+	 * Quote a string.
+	 * 
+	 * Shorthand for AbstractQueryBuilder.quote( s )
+	 * 
+	 * @see AbstractQueryBuilder#quote(String)
+	 * 
+	 * 
+	 * @param s
+	 *            the string to quote.
+	 * @return the quoted string.
+	 */
+	public String quote(String s) {
+		return AbstractQueryBuilder.quote(s);
+	}
+
+	/**
+	 * Add a quad to the insert statement.
+	 * 
+	 * Arguments are converted to nodes using the makeNode() method.
+	 * 
+	 * @see #makeNode(Object)
+	 * @param g
+	 *            the graph
+	 * @param s
+	 *            the subject
+	 * @param p
+	 *            the predicate
+	 * @param o
+	 *            the object
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addInsert(Object g, Object s, Object p, Object o) {
+		return addInsert(new Quad(makeNode(g), makeNode(s), makeNode(p), makeNode(o)));
+	}
+
+	/**
+	 * Add a quad to the insert statement.
+	 * 
+	 * 
+	 * @param quad
+	 *            the quad to add.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addInsert(Quad quad) {
+		inserts.add(new SingleQuadHolder(quad));
+		return this;
+	}
+
+	/**
+	 * Add a triple to the insert statement.
+	 * 
+	 * Arguments are converted to nodes using the makeNode() method.
+	 * 
+	 * @see #makeNode(Object)
+	 * @param s
+	 *            the subject
+	 * @param p
+	 *            the predicate
+	 * @param o
+	 *            the object
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addInsert(Object s, Object p, Object o) {
+		addInsert(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+		return this;
+	}
+
+	/**
+	 * Add a triple to the insert statement.
+	 * 
+	 * @param t
+	 *            the triple to add.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addInsert(Triple t) {
+		inserts.add(new SingleQuadHolder( t ));
+		return this;
+	}
+
+	/**
+	 * Add a triple in a specified graph to the insert statement.
+	 * 
+	 * The graph object is converted by a call to makeNode().
+	 * 
+	 * @see #makeNode(Object)
+	 * @param g
+	 *            the graph for the triple.
+	 * @param t
+	 *            the triple to add.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addInsert(Object g, Triple t) {
+		Quad q = new Quad(AbstractQueryBuilder.makeNode(g, prefixHandler.getPrefixes()), t);
+		inserts.add(new SingleQuadHolder(q));
+		return this;
+	}
+
+	/**
+	 * Add the statements from the where clause in the specified query builder
+	 * to the insert statement.
+	 * 
+	 * @see #makeNode(Object)
+	 * @param queryBuilder
+	 *            The query builder to extract the where clause from.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addInsert(AbstractQueryBuilder<?> queryBuilder) {
+		inserts.add(new QBQuadHolder( queryBuilder));
+		return this;
+	}
+
+	/**
+	 * Add the statements from the where clause in the specified query builder
+	 * to the insert statements for the specified graph.
+	 * 
+	 * The graph object is converted by a call to makeNode().
+	 * 
+	 * @see #makeNode(Object)
+	 * @param graph
+	 *            the graph to add the statements to.
+	 * @param queryBuilder
+	 *            The query builder to extract the where clause from.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addInsert(Object graph, AbstractQueryBuilder<?> queryBuilder) {
+		inserts.add(new QBQuadHolder(AbstractQueryBuilder.makeNode(graph, prefixHandler.getPrefixes()), queryBuilder));
+		return this;
+	}
+
+	/**
+	 * Add a quad to the delete statement.
+	 * 
+	 * Arguments are converted to nodes using the makeNode() method.
+	 * 
+	 * @see #makeNode(Object)
+	 * @param g
+	 *            the graph
+	 * @param s
+	 *            the subject
+	 * @param p
+	 *            the predicate
+	 * @param o
+	 *            the object
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addDelete(Object g, Object s, Object p, Object o) {
+		return addDelete(new Quad(AbstractQueryBuilder.makeNode(g, prefixHandler.getPrefixes()),
+				AbstractQueryBuilder.makeNode(s, prefixHandler.getPrefixes()),
+				AbstractQueryBuilder.makeNode(p, prefixHandler.getPrefixes()),
+				AbstractQueryBuilder.makeNode(o, prefixHandler.getPrefixes())));
+	}
+
+	/**
+	 * Add a quad to the delete statement.
+	 * 
+	 * 
+	 * @param quad
+	 *            the quad to add.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addDelete(Quad quad) {
+		deletes.add(new SingleQuadHolder(quad));
+		return this;
+	}
+
+	/**
+	 * Add a triple to the delete statement.
+	 * 
+	 * Arguments are converted to nodes using the makeNode() method.
+	 * 
+	 * @see #makeNode(Object)
+	 * @param s
+	 *            the subject
+	 * @param p
+	 *            the predicate
+	 * @param o
+	 *            the object
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addDelete(Object s, Object p, Object o) {
+		addDelete(new Triple(AbstractQueryBuilder.makeNode(s, prefixHandler.getPrefixes()),
+				AbstractQueryBuilder.makeNode(p, prefixHandler.getPrefixes()),
+				AbstractQueryBuilder.makeNode(o, prefixHandler.getPrefixes())));
+		return this;
+	}
+
+	/**
+	 * Add a triple to the delete statement.
+	 * 
+	 * 
+	 * @param t
+	 *            the triple to add.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addDelete(Triple t) {
+		deletes.add(new SingleQuadHolder(t));
+		return this;
+	}
+
+	/**
+	 * Add a triple in a specified graph to the delete statement.
+	 * 
+	 * The graph object is converted by a call to makeNode().
+	 * 
+	 * @see #makeNode(Object)
+	 * @param g
+	 *            the graph for the triple.
+	 * @param t
+	 *            the triple to add.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addDelete(Object g, Triple t) {
+		Quad q = new Quad(AbstractQueryBuilder.makeNode(g, prefixHandler.getPrefixes()), t);
+		deletes.add(new SingleQuadHolder(q));
+		return this;
+	}
+
+	/**
+	 * Add the statements from the where clause in the specified query builder
+	 * to the delete statement.
+	 * 
+	 * @see #makeNode(Object)
+	 * @param queryBuilder
+	 *            The query builder to extract the where clause from.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addDelete(AbstractQueryBuilder<?> queryBuilder) {
+		deletes.add(new QBQuadHolder( queryBuilder));
+		return this;
+	}
+
+	/**
+	 * Add the statements from the where clause in the specified query builder
+	 * to the delete statements for the specified graph.
+	 * 
+	 * The graph object is converted by a call to makeNode().
+	 * 
+	 * @see #makeNode(Object)
+	 * @param graph
+	 *            the graph to add the statements to.
+	 * @param queryBuilder
+	 *            The query builder to extract the where clause from.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder addDelete(Object graph, AbstractQueryBuilder<?> queryBuilder) {
+		deletes.add(new QBQuadHolder(AbstractQueryBuilder.makeNode(graph, prefixHandler.getPrefixes()), queryBuilder));
+		return this;
+	}
+
+	/**
+	 * Add the prefix to the prefix mapping.
+	 * 
+	 * @param pfx
+	 *            the prefix to add.
+	 * @param uri
+	 *            the uri for the prefix.
+	 * @return this builder for chaining
+	 */
+	public UpdateBuilder addPrefix(String pfx, Resource uri) {
+		return addPrefix(pfx, uri.getURI());
+	}
+
+	/**
+	 * Add the prefix to the prefix mapping.
+	 * 
+	 * @param pfx
+	 *            the prefix to add.
+	 * @param uri
+	 *            the uri for the prefix.
+	 * @return this builder for chaining
+	 */
+	public UpdateBuilder addPrefix(String pfx, Node uri) {
+		return addPrefix(pfx, uri.getURI());
+	}
+
+	/**
+	 * Add the prefix to the prefix mapping.
+	 * 
+	 * @param pfx
+	 *            the prefix to add.
+	 * @param uri
+	 *            the uri for the prefix.
+	 * @return this builder for chaining
+	 */
+	public UpdateBuilder addPrefix(String pfx, String uri) {
+		prefixHandler.addPrefix(pfx, uri);
+		return this;
+	}
+
+	/**
+	 * Add the prefixes to the prefix mapping.
+	 * 
+	 * @param prefixes
+	 *            the prefixes to add.
+	 * @return this builder for chaining
+	 */
+
+	public UpdateBuilder addPrefixes(Map<String, String> prefixes) {
+		prefixHandler.addPrefixes(prefixes);
+		return this;
+	}
+
+	/**
+	 * Get an ExprFactory that uses the prefixes from this builder.
+	 * 
+	 * @return the EpxressionFactory.
+	 */
+	public ExprFactory getExprFactory() {
+		return prefixHandler.getExprFactory();
+	}
+
+	/**
+	 * Set a variable replacement. During build all instances of var in the
+	 * query will be replaced with value. If value is null the replacement is
+	 * cleared.
+	 * 
+	 * @param var
+	 *            The variable to replace
+	 * @param value
+	 *            The value to replace it with or null to remove the
+	 *            replacement.
+	 */
+	public void setVar(Var var, Node value) {
+		if (value == null) {
+			values.remove(var);
+		} else {
+			values.put(var, value);
+		}
+	}
+
+	/**
+	 * Set a variable replacement. During build all instances of var in the
+	 * query will be replaced with value. If value is null the replacement is
+	 * cleared.
+	 * 
+	 * See {@link #makeVar} for conversion of the var param. See
+	 * {@link #makeNode} for conversion of the value param.
+	 * 
+	 * @param var
+	 *            The variable to replace.
+	 * @param value
+	 *            The value to replace it with or null to remove the
+	 *            replacement.
+	 */
+	public void setVar(Object var, Object value) {
+		if (value == null) {
+			setVar(AbstractQueryBuilder.makeVar(var), null);
+		} else {
+			setVar(AbstractQueryBuilder.makeVar(var),
+					AbstractQueryBuilder.makeNode(value, prefixHandler.getPrefixes()));
+		}
+	}
+
+	private Quad check(Quad q) {
+		if (Var.isVar(q.getGraph()))
+			throw new QueryParseException("Variables not permitted in data quad", -1, -1);
+		if (Var.isVar(q.getSubject()) || Var.isVar(q.getPredicate()) || Var.isVar(q.getObject()))
+			throw new QueryParseException("Variables not permitted in data quad", -1, -1);
+		if (q.getSubject().isLiteral())
+			throw new QueryParseException("Literals not allowed as subjects in data", -1, -1);
+		return q;
+	}
+
+	/**
+	 * Add all where attributes from the Where Handler argument.
+	 * 
+	 * @param whereHandler
+	 *            The Where Handler to copy from.
+	 */
+	public UpdateBuilder addAll(WhereHandler whereHandler) {
+		whereProcessor.addAll(whereHandler);
+		return this;
+	}
+
+	/**
+	 * Add the triple path to the where clause
+	 * 
+	 * @param t
+	 *            The triple path to add.
+	 * @throws IllegalArgumentException
+	 *             If the triple path is not a valid triple path for a where
+	 *             clause.
+	 */
+	public UpdateBuilder addWhere(TriplePath t) throws IllegalArgumentException {
+		whereProcessor.addWhere(t);
+		return this;
+	}
+
+	/**
+	 * Add the triple path to the where clause
+	 * 
+	 * @param t
+	 *            The triple path to add.
+	 * @throws IllegalArgumentException
+	 *             If the triple path is not a valid triple path for a where
+	 *             clause.
+	 */
+	public UpdateBuilder addWhere(WhereClause<?> whereClause) throws IllegalArgumentException {
+		whereProcessor.addAll(whereClause.getWhereHandler());
+		return this;
+	}
+	/**
+	 * Add an optional triple to the where clause
+	 * 
+	 * @param t
+	 *            The triple path to add.
+	 * @return The Builder for chaining.
+	 * @throws IllegalArgumentException
+	 *             If the triple is not a valid triple for a where clause.
+	 */
+	public UpdateBuilder addOptional(TriplePath t) throws IllegalArgumentException {
+		whereProcessor.addOptional(t);
+		return this;
+	}
+
+	/**
+	 * Add the contents of a where handler as an optional statement.
+	 * 
+	 * @param whereHandler
+	 *            The where handler to use as the optional statement.
+	 */
+	public UpdateBuilder addOptional(WhereHandler whereHandler) {
+		whereProcessor.addOptional(whereHandler);
+		return this;
+	}
+
+	/**
+	 * Add an expression string as a filter.
+	 * 
+	 * @param expression
+	 *            The expression string to add.
+	 * @return The Builder for chaining.
+	 * @throws ParseException
+	 *             If the expression can not be parsed.
+	 */
+	public UpdateBuilder addFilter(String expression) throws ParseException {
+		whereProcessor.addFilter(expression);
+		return this;
+	}
+
+	/**
+	 * Add a subquery to the where clause.
+	 * 
+	 * @param subQuery
+	 *            The sub query to add.
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addSubQuery(AbstractQueryBuilder<?> subQuery) {
+		whereProcessor.addSubQuery(subQuery);
+		return this;
+	}
+
+	/**
+	 * Add a union to the where clause.
+	 * 
+	 * @param subQuery
+	 *            The subquery to add as the union.
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addUnion(AbstractQueryBuilder<?> subQuery) {
+		whereProcessor.addUnion(subQuery);
+		return this;
+	}
+
+	/**
+	 * Add a graph to the where clause.
+	 * 
+	 * @param graph
+	 *            The name of the graph.
+	 * @param subQuery
+	 *            The where handler that defines the graph.
+	 */
+	public UpdateBuilder addGraph(Node graph, WhereHandler subQuery) {
+		whereProcessor.addGraph(graph, subQuery);
+		return this;
+	}
+
+	/**
+	 * Add a binding to the where clause.
+	 * 
+	 * @param expr
+	 *            The expression to bind.
+	 * @param var
+	 *            The variable to bind it to.
+	 */
+	public UpdateBuilder addBind(Expr expr, Var var) {
+		whereProcessor.addBind(expr, var);
+		return this;
+	}
+
+	/**
+	 * Add a binding to the where clause.
+	 * 
+	 * @param expression
+	 *            The expression to bind.
+	 * @param var
+	 *            The variable to bind it to.
+	 * @throws ParseException
+	 */
+	public UpdateBuilder addBind(String expression, Var var) throws ParseException {
+		whereProcessor.addBind(expression, var);
+		return this;
+	}
+
+	/**
+	 * Create a list node from a list of objects as per RDF Collections.
+	 * 
+	 * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#collections
+	 * 
+	 * See {@link AbstractQueryBuilder#makeNode} for conversion of the param
+	 * values.
+	 * <p>
+	 * usage:
+	 * <ul>
+	 * <li>list( param1, param2, param3, ... )</li>
+	 * <li>addWhere( list( param1, param2, param3, ... ), p, o )</li>
+	 * <li>addOptional( list( param1, param2, param3, ... ), p, o )</li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @param objs
+	 *            the list of objects for the list.
+	 * 
+	 * @param objs
+	 *            the list of objects for the list.
+	 * @return the first blank node in the list.
+	 */
+	public Node list(Object... objs) {
+		Node retval = NodeFactory.createBlankNode();
+		Node lastObject = retval;
+		for (int i = 0; i < objs.length; i++) {
+			Node n = makeNode(objs[i]);
+			addWhere(new TriplePath(new Triple(lastObject, RDF.first.asNode(), n)));
+			if (i + 1 < objs.length) {
+				Node nextObject = NodeFactory.createBlankNode();
+				addWhere(new TriplePath(new Triple(lastObject, RDF.rest.asNode(), nextObject)));
+				lastObject = nextObject;
+			} else {
+				addWhere(new TriplePath(new Triple(lastObject, RDF.rest.asNode(), RDF.nil.asNode())));
+			}
+
+		}
+
+		return retval;
+	}
+
+	/**
+	 * Adds a triple to the where clause.
+	 * 
+	 * @param t
+	 *            The triple path to add
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addWhere(Triple t) {
+		return addWhere(new TriplePath(t));
+	}
+
+	/**
+	 * Adds a triple to the where clause.
+	 * 
+	 * @param t
+	 *            The triple to add
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addWhere(FrontsTriple t) {
+		return addWhere(t.asTriple());
+	}
+
+	/**
+	 * Adds a triple or triple path to the where clause.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeTriplePath} for conversion of the
+	 * param values.
+	 * 
+	 * @param s
+	 *            The subject.
+	 * @param p
+	 *            The predicate.
+	 * @param o
+	 *            The object.
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addWhere(Object s, Object p, Object o) {
+		return addWhere(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+	}
+
+	/**
+	 * Adds an optional triple to the where clause.
+	 * 
+	 * @param t
+	 *            The triple to add
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addOptional(Triple t) {
+		return addOptional(new TriplePath(t));
+	}
+
+	/**
+	 * Adds an optional triple as to the where clause.
+	 * 
+	 * @param t
+	 *            The triple to add
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addOptional(FrontsTriple t) {
+		return addOptional(t.asTriple());
+	}
+
+	/**
+	 * Adds an optional triple or triple path to the where clause.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeTriplePath} for conversion of the
+	 * param values.
+	 * 
+	 * @param s
+	 *            The subject.
+	 * @param p
+	 *            The predicate.
+	 * @param o
+	 *            The object.
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addOptional(Object s, Object p, Object o) {
+		return addOptional(new Triple(makeNode(s), makeNode(p), makeNode(o)));
+	}
+
+	/**
+	 * Adds an optional group pattern to the where clause.
+	 * 
+	 * @param t
+	 *            The select builder to add as an optional pattern
+	 * @return The Builder for chaining.
+	 */
+	public UpdateBuilder addOptional(AbstractQueryBuilder<?> t) {
+		whereProcessor.addOptional(t.getWhereHandler());
+		return this;
+	}
+
+	/**
+	 * Adds a filter to the where clause
+	 * 
+	 * Use ExprFactory or NodeValue static or the AbstractQueryBuilder.makeExpr
+	 * methods to create the expression.
+	 * 
+	 * @see ExprFactory
+	 * @see org.apache.jena.sparql.expr.NodeValue
+	 * @see AbstractQueryBuilder#makeExpr(String)
+	 * 
+	 * @param expression
+	 *            the expression to evaluate for the filter.
+	 * @return @return The Builder for chaining.
+	 */
+	public UpdateBuilder addFilter(Expr expression) {
+		whereProcessor.addFilter(expression);
+		return this;
+	}
+
+	/**
+	 * Add a graph statement to the query as per
+	 * http://www.w3.org/TR/2013/REC-sparql11
+	 * -query-20130321/#rGraphGraphPattern.
+	 * 
+	 * See {@link AbstractQueryBuilder#makeNode} for conversion of the graph
+	 * param.
+	 * 
+	 * @param graph
+	 *            The iri or variable identifying the graph.
+	 * @param subQuery
+	 *            The graph to add.
+	 * @return This builder for chaining.
+	 */
+	public UpdateBuilder addGraph(Object graph, AbstractQueryBuilder<?> subQuery) {
+		whereProcessor.addGraph(makeNode(graph), subQuery.getWhereHandler());
+		return this;
+	}
+
+	/**
+	 * Add a bind statement to the query *
+	 * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rGraphGraphPattern.
+	 * 
+	 * @param expression
+	 *            The expression to bind to the var.
+	 * @param var
+	 *            The variable to bind to.
+	 * @return This builder for chaining.
+	 */
+	public UpdateBuilder addBind(Expr expression, Object var) {
+		whereProcessor.addBind(expression, makeVar(var));
+		return this;
+	}
+
+	/**
+	 * Add a bind statement to the query
+	 * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rGraphGraphPattern.
+	 * 
+	 * @param expression
+	 *            The expression to bind to the var.
+	 * @param var
+	 *            The variable to bind to.
+	 * @return This builder for chaining.
+	 * @throws ParseException
+	 */
+	public UpdateBuilder addBind(String expression, Object var) throws ParseException {
+		whereProcessor.addBind(expression, makeVar(var));
+		return this;
+	}
+
+	/**
+	 * Add a minus clause to the query.
+	 * 
+	 * https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rMinusGraphPattern
+	 * 
+	 * @param t
+	 *            The select builder to add as a minus pattern
+	 * @return this builder for chaining
+	 */
+	public UpdateBuilder addMinus(AbstractQueryBuilder<?> t) {
+		whereProcessor.addMinus(t);
+		return this;
+	}
+
+	/**
+	 * Specify the graph for all inserts and deletes.
+	 * 
+	 * 
+	 * @See Quad#defaultGraphNodeGenerated
+	 * @param iri
+	 *            the IRI for the graph to use.
+	 * @return this builder for chaining.
+	 */
+	public UpdateBuilder with(Object iri) {
+		if (iri == null) {
+			with = null;
+		}
+		Node n = makeNode(iri);
+		if (n.isLiteral()) {
+			throw new IllegalArgumentException(String.format("IRI '%s' must not be a literal", iri));
+		}
+		with = n;
+		return this;
+	}
+
+	/**
+	 * Create a DeleteWhere from the where clause.
+	 * @return a DeleteWhere update.
+	 */
+	public UpdateDeleteWhere buildDeleteWhere()
+	{
+		QuadAcc quadAcc = new QuadAcc( whereProcessor.getQuads().toList() );
+		return new UpdateDeleteWhere( quadAcc );
+	}
+	
+	/**
+	 * Create a DeleteWhere from the where clause.
+	 * @param queryBuilder the query builder to extract the where clause from.
+	 * @return a DeleteWhere update.
+	 */
+	public UpdateDeleteWhere buildDeleteWhere( AbstractQueryBuilder<?> queryBuilder)
+	{	
+		QuadAcc quadAcc = new QuadAcc( new QBQuadHolder( queryBuilder ).getQuads().toList() );
+		return new UpdateDeleteWhere( quadAcc );
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
index b5f04ac..95d8bc7 100644
--- a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/handlers/WhereHandler.java
@@ -57,6 +57,15 @@ public class WhereHandler implements Handler {
 	public WhereHandler(Query query) {
 		this.query = query;
 	}
+	
+	/**
+	 * Get the query pattern from this where handler.
+	 * @return the query pattern
+	 */
+	public Element getQueryPattern()
+	{
+		 return query.getQueryPattern();
+	}
 
 	/**
 	 * Add all where attributes from the Where Handler argument.
@@ -273,7 +282,7 @@ public class WhereHandler implements Handler {
 	 *            The sub query to convert
 	 * @return THe converted element.
 	 */
-	private ElementSubQuery makeSubQuery(AbstractQueryBuilder<?> subQuery) {
+	public ElementSubQuery makeSubQuery(AbstractQueryBuilder<?> subQuery) {
 		Query q = new Query();
 		SelectHandler sh = subQuery.getHandlerBlock().getSelectHandler();
 		if (sh != null)
@@ -421,12 +430,18 @@ public class WhereHandler implements Handler {
 		return retval;
 	}
 	
-	public void addMinus( AbstractQueryBuilder<?> t )
+	/**
+	 * Add a minus operation to the where clause.
+	 * The prolog will be updated with the prefixes from the abstract query builder.
+	 * 
+	 * @param qb the abstract builder that defines the data to subtract.
+	 */
+	public void addMinus( AbstractQueryBuilder<?> qb )
 	{
 		PrologHandler ph = new PrologHandler(query);
-		ph.addPrefixes( t.getPrologHandler().getPrefixes() );
+		ph.addPrefixes( qb.getPrologHandler().getPrefixes() );
 		ElementGroup clause = getClause();
-		ElementMinus minus = new ElementMinus(t.getWhereHandler().getClause());
+		ElementMinus minus = new ElementMinus(qb.getWhereHandler().getClause());
 		clause.addElement(minus);
 	}
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/PrefixHandler.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/PrefixHandler.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/PrefixHandler.java
new file mode 100644
index 0000000..5713e04
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/PrefixHandler.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.updatebuilder;
+
+import java.util.Map;
+
+import org.apache.jena.arq.querybuilder.ExprFactory;
+import org.apache.jena.shared.PrefixMapping ;
+
+/**
+ * The prefix handler for the updatebuilder class
+ *
+ */
+public class PrefixHandler {
+
+	// the prefix mapping we are handling
+	private final PrefixMapping pMap;
+
+	/**
+	 * Constructor.
+	 * <b>May modify the contents of the provided prefix mapping</b>
+	 * @param pMap The prefix map to handle.
+	 */
+	public PrefixHandler(PrefixMapping pMap) {
+		this.pMap = pMap;
+	}
+	
+	/**
+	 * Constructor.  Creates and empty prefix mapping
+	 */
+	public PrefixHandler() {
+		this.pMap = PrefixMapping.Factory.create();
+	}
+
+	/**
+	 * get the canonical prefix name.  
+	 * 
+	 * Removes ':' from the end of the name if present.
+	 * 
+	 * @param x The prefix name
+	 * @return The prefix name with the trialing ':' removed.
+	 */
+	private static String canonicalPfx(String x) {
+		if (x.endsWith(":"))
+			return x.substring(0, x.length() - 1);
+		return x;
+	}
+
+	
+	/**
+	 * Add a prefix to the prefix mapping.
+	 * @param pfx The prefix to add.
+	 * @param uri The uri to resolve the prefix to.
+	 */
+	public void addPrefix(String pfx, String uri) {
+		pMap.setNsPrefix(canonicalPfx(pfx), uri);
+	}
+	
+	/**
+	 * Clear the prefix mapping.
+	 */
+	public void clearPrefixes() {
+		pMap.clearNsPrefixMap();
+	}
+
+	/**
+	 * Add the map of prefixes to the query prefixes.
+	 * @param prefixes The map of prefixs to URIs.
+	 */
+	public void addPrefixes(Map<String, String> prefixes) {
+		for (Map.Entry<String, String> e : prefixes.entrySet()) {
+			addPrefix(e.getKey(), e.getValue());
+		}
+	}
+	
+	/**
+	 * Get the prefix mapping
+	 * @return the prefix mapping object.
+	 */
+	public PrefixMapping getPrefixes() {
+		return pMap;
+	}
+	
+	/**
+	 * Get the expression factory based on the prefix mapping.
+	 * @return an Expression Factory.
+	 */
+	public ExprFactory getExprFactory() {
+		return new ExprFactory( pMap );
+	}
+
+	/**
+	 * Add prefixes from a prefix mapping.
+	 * @param prefixes THe prefix mapping to add from.
+	 */
+	public void addPrefixes(PrefixMapping prefixes) {
+		pMap.setNsPrefixes(prefixes);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QBQuadHolder.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QBQuadHolder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QBQuadHolder.java
new file mode 100644
index 0000000..d6584dd
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QBQuadHolder.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.updatebuilder;
+
+import java.util.Map;
+
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.graph.Node;
+import org.apache.jena.query.Query;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.core.Var;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/**
+ * An QuadHolder that manages AbstractQueryBuilder data.
+ *
+ */
+public class QBQuadHolder implements QuadHolder {
+
+	private final AbstractQueryBuilder<?> qb;
+	private Node defaultGraphName;
+	
+	/**
+	 * Constructor.
+	 * @param graph the default graph name for the triples
+	 * @param qb the AbstractQueryBuilder that is providing the triples.
+	 */
+	public QBQuadHolder( Node graph, AbstractQueryBuilder<?> qb )
+	{
+		this.qb = qb;
+		this.defaultGraphName = graph;
+	}
+	
+	/**
+	 * Constructor.
+	 *  Uses  Quad.defaultGraphNodeGenerated for the graph name.
+	 * 
+	 * @see  Quad#defaultGraphNodeGenerated 
+	 * @param qb the AbstractQueryBuilder that is providing the triples.
+	 */
+	public QBQuadHolder( AbstractQueryBuilder<?> qb )
+	{
+		this( Quad.defaultGraphNodeGenerated, qb );
+	}
+	
+	@Override
+	public ExtendedIterator<Quad> getQuads() {
+		Query q = qb.build();
+		QuadIteratorBuilder builder = new QuadIteratorBuilder(defaultGraphName);
+		q.getQueryPattern().visit(builder);
+		return builder.iter;
+	}
+
+	@Override
+	public QuadHolder setValues(Map<Var, Node> values) {
+		qb.clearValues();
+		for (Map.Entry<Var, Node> entry : values.entrySet())
+		{
+			qb.setVar(entry.getKey(), entry.getValue());
+		}
+		return this;
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadHolder.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadHolder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadHolder.java
new file mode 100644
index 0000000..607898d
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadHolder.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.updatebuilder;
+
+import java.util.Map;
+
+import org.apache.jena.graph.Node;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.core.Var;
+import org.apache.jena.util.iterator.ExtendedIterator;
+
+/**
+ * An interface that defines a holder of quads.
+ *
+ */
+public interface QuadHolder {
+
+	/**
+	 * Get an extended iterator over the quads this holder holds.
+	 * @return the extended iterator.
+	 */
+	public ExtendedIterator<Quad> getQuads();
+	
+	/**
+	 * Apply values to the variables in the quads held by this holder.
+	 * May return this holder or a new holder instance.
+	 * @param values the values to set.
+	 * @return a QuadHolder in which the variables have been replaced.
+	 */
+	public QuadHolder setValues(Map<Var, Node> values);
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadIteratorBuilder.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadIteratorBuilder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadIteratorBuilder.java
new file mode 100644
index 0000000..cc7c2ea
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/QuadIteratorBuilder.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.updatebuilder;
+
+import java.util.function.Function;
+
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.query.Query;
+import org.apache.jena.query.QueryParseException;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.core.TriplePath;
+import org.apache.jena.sparql.syntax.Element;
+import org.apache.jena.sparql.syntax.ElementAssign;
+import org.apache.jena.sparql.syntax.ElementBind;
+import org.apache.jena.sparql.syntax.ElementData;
+import org.apache.jena.sparql.syntax.ElementDataset;
+import org.apache.jena.sparql.syntax.ElementExists;
+import org.apache.jena.sparql.syntax.ElementFilter;
+import org.apache.jena.sparql.syntax.ElementGroup;
+import org.apache.jena.sparql.syntax.ElementMinus;
+import org.apache.jena.sparql.syntax.ElementNamedGraph;
+import org.apache.jena.sparql.syntax.ElementNotExists;
+import org.apache.jena.sparql.syntax.ElementOptional;
+import org.apache.jena.sparql.syntax.ElementPathBlock;
+import org.apache.jena.sparql.syntax.ElementService;
+import org.apache.jena.sparql.syntax.ElementSubQuery;
+import org.apache.jena.sparql.syntax.ElementTriplesBlock;
+import org.apache.jena.sparql.syntax.ElementUnion;
+import org.apache.jena.sparql.syntax.ElementVisitor;
+import org.apache.jena.util.iterator.ExtendedIterator;
+import org.apache.jena.util.iterator.WrappedIterator;
+
+/**
+ * A class to construct a quad iterator from the elements.
+ *
+ */
+class QuadIteratorBuilder implements ElementVisitor {
+	// the default graph name
+	private final Node defaultGraph;
+	// the extended iterator we will add to.
+	ExtendedIterator<Quad> iter = WrappedIterator.emptyIterator();
+	
+	// a function to map triples to quads using the default graph name.
+	private Function<Triple,Quad> MAP = 
+		new Function<Triple,Quad>(){
+	
+		@Override
+		public Quad apply(Triple triple) {
+			return new Quad( defaultGraph, triple );
+		}
+	};
+	
+	/**
+	 * Constructor.
+	 * @param defaultGraph the default graph name.
+	 */
+	QuadIteratorBuilder(Node defaultGraph)
+	{
+		this.defaultGraph = defaultGraph;
+	}
+	
+	
+	@Override
+	public void visit(ElementTriplesBlock el) {
+		iter = iter.andThen( WrappedIterator.create(el.getPattern().getList().iterator())
+		.mapWith( MAP ));
+	}
+
+	@Override
+	public void visit(ElementPathBlock el) {
+		for (TriplePath pth : el.getPattern().getList())
+		{
+			if ( ! pth.isTriple())
+			{
+	            throw new QueryParseException("Paths not permitted in data quad", -1, -1) ;   
+			}
+		}
+		iter = iter.andThen( 
+				WrappedIterator.create(el.getPattern().getList().iterator())
+				.mapWith( pth -> pth.asTriple() )
+				.mapWith( MAP ));
+	}
+
+	@Override
+	public void visit(ElementFilter el) {
+        throw new QueryParseException("Paths not permitted in data quad", -1, -1) ;   
+	}
+
+	@Override
+	public void visit(ElementAssign el) {
+        throw new QueryParseException("element assignment not permitted in data quad", -1, -1) ;   
+	}
+
+	@Override
+	public void visit(ElementBind el) {
+        throw new QueryParseException("bind not permitted in data quad", -1, -1) ;   
+		
+	}
+
+	@Override
+	public void visit(ElementData el) {
+        throw new QueryParseException("element data not permitted in data quad", -1, -1) ;   
+	}
+
+	@Override
+	public void visit(ElementUnion el) {
+		for (Element e : el.getElements())
+		{
+			e.visit( this );
+		}
+	}
+
+	@Override
+	public void visit(ElementOptional el) {
+        throw new QueryParseException("optional not permitted in data quad", -1, -1) ;   
+	}
+
+	@Override
+	public void visit(ElementGroup el) {
+		for (Element e : el.getElements())
+		{
+			e.visit( this );
+		}
+	}
+
+	@Override
+	public void visit(ElementDataset el) {
+		iter = iter.andThen(el.getDataset().find());			
+	}
+
+	@Override
+	public void visit(ElementNamedGraph el) {
+		QuadIteratorBuilder bldr = new QuadIteratorBuilder( el.getGraphNameNode());
+		el.getElement().visit(bldr);
+		iter = iter.andThen( bldr.iter );
+	}
+
+	@Override
+	public void visit(ElementExists el) {
+        throw new QueryParseException("exists not permitted in data quad", -1, -1) ;   
+	}
+
+	@Override
+	public void visit(ElementNotExists el) {
+        throw new QueryParseException("not exists not permitted in data quad", -1, -1) ;   
+	}
+
+	@Override
+	public void visit(ElementMinus el) {
+		throw new QueryParseException("minus not permitted in data quad", -1, -1) ;		
+	}
+
+	@Override
+	public void visit(ElementService el) {
+		throw new QueryParseException("service not permitted in data quad", -1, -1) ;		
+	}
+
+	@Override
+	public void visit(ElementSubQuery el) {
+		Query q = el.getQuery();
+		q.getQueryPattern().visit( this );
+	}
+	
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/SingleQuadHolder.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/SingleQuadHolder.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/SingleQuadHolder.java
new file mode 100644
index 0000000..234de60
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/SingleQuadHolder.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.updatebuilder;
+
+import java.util.Map;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.core.Var;
+import org.apache.jena.util.iterator.ExtendedIterator;
+import org.apache.jena.util.iterator.SingletonIterator;
+
+/**
+ * A QuadHolder implementation for a single quad.
+ */
+public class SingleQuadHolder implements QuadHolder{
+
+	private Quad quad;
+	private Quad updated;
+
+	/**
+	 * Constructor for a single quad.
+	 * @param quad the quad to hold.
+	 */
+	public SingleQuadHolder( Quad quad )
+	{
+		this.quad = quad;
+	}
+
+	/**
+	 * Constructor from a triple
+	 * Uses  Quad.defaultGraphNodeGenerated for the graph name.
+	 * 
+	 * @see  Quad#defaultGraphNodeGenerated 
+	 * @param triple the triple to convert to a quad.
+	 */
+	public SingleQuadHolder( Triple triple )
+	{
+		this.quad = new Quad( Quad.defaultGraphNodeGenerated, triple );
+	}
+
+	
+	/**
+	 * Constructor from a triple
+	 * @param graph the graph name to use for the  triple 
+	 * @param triple the triple to convert to a quad.
+	 */
+	public SingleQuadHolder( Node graph, Triple triple )
+	{
+		this.quad = new Quad( graph, triple );
+	}
+	
+	@Override
+	public ExtendedIterator<Quad> getQuads() {
+		return new SingletonIterator<Quad>(updated==null?quad:updated);
+	}
+
+	// convert variable if in map
+	private Node mapValue( Node n, Map<Var, Node> values)
+	{
+		Node retval = null;
+		if (n.isVariable())
+		{
+			Var v = Var.alloc(n);
+			retval = values.get(v);
+		}
+		return retval==null?n:retval;
+	}
+	
+	@Override
+	public QuadHolder setValues(Map<Var, Node> values) {
+		updated = new Quad( 
+				mapValue( quad.getGraph(), values),
+				mapValue( quad.getSubject(), values),
+				mapValue( quad.getPredicate(), values),
+				mapValue( quad.getObject(), values)
+				);
+		return this;
+	}
+
+	
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereProcessor.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereProcessor.java b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereProcessor.java
new file mode 100644
index 0000000..b6e40e4
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/main/java/org/apache/jena/arq/querybuilder/updatebuilder/WhereProcessor.java
@@ -0,0 +1,433 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jena.arq.querybuilder.updatebuilder;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
+import org.apache.jena.arq.querybuilder.clauses.SelectClause;
+import org.apache.jena.arq.querybuilder.handlers.WhereHandler;
+import org.apache.jena.arq.querybuilder.rewriters.ElementRewriter;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.query.Query;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.core.TriplePath;
+import org.apache.jena.sparql.core.Var;
+import org.apache.jena.sparql.expr.Expr;
+import org.apache.jena.sparql.lang.sparql_11.ParseException;
+import org.apache.jena.sparql.syntax.*;
+import org.apache.jena.sparql.util.ExprUtils;
+import org.apache.jena.util.iterator.ExtendedIterator;
+import org.apache.jena.util.iterator.NiceIterator;
+import org.apache.jena.vocabulary.RDF;
+
+/**
+ * The where processor. Generally handles update where clause.
+ * 
+ * @see <a href=
+ *      "http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#rGroupGraphPattern">
+ *      SPARQL 11 Query Language - Group Graph Pattern</a>
+ *
+ */
+public class WhereProcessor implements QuadHolder {
+
+	private Element whereClause;
+	private final PrefixHandler prefixHandler;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param prefixHandler
+	 *            the prefix handler to use.
+	 */
+	public WhereProcessor(PrefixHandler prefixHandler) {
+		this.prefixHandler = prefixHandler;
+	}
+
+	/**
+	 * True if there are no elements in the where processor.
+	 * 
+	 * @return true if there are no elements.
+	 */
+	public boolean isEmpty() {
+		return whereClause == null || (whereClause instanceof ElementGroup && ((ElementGroup) whereClause).isEmpty());
+	}
+
+	@Override
+	public ExtendedIterator<Quad> getQuads() {
+		return getQuads( Quad.defaultGraphNodeGenerated);
+	}
+	
+	public ExtendedIterator<Quad> getQuads( Node defaultGraphName ) {
+		if (isEmpty())
+		{
+			return NiceIterator.emptyIterator();
+		}
+		QuadIteratorBuilder builder = new QuadIteratorBuilder(defaultGraphName);
+		whereClause.visit(builder);
+		return builder.iter;
+	}
+	/**
+	 * Add all where attributes from the Where Handler argument.
+	 * 
+	 * @param whereHandler
+	 *            The Where Handler to copy from.
+	 */
+	public void addAll(WhereHandler whereHandler) {
+
+		Element e = whereHandler.getQueryPattern();
+		if (e != null) {
+			// clone the Element
+			ElementRewriter rewriter = new ElementRewriter(Collections.emptyMap());
+			e.visit(rewriter);
+			Element clone = rewriter.getResult();
+
+			if (whereClause == null) {
+				whereClause = clone;
+			} else {
+				ElementGroup eg = null;
+				if (whereClause instanceof ElementGroup) {
+					eg = (ElementGroup) whereClause;
+				} else {
+					eg = new ElementGroup();
+					eg.addElement(whereClause);
+				}
+				if (clone instanceof ElementGroup) {
+					for (Element ele : ((ElementGroup) clone).getElements()) {
+						eg.addElement(ele);
+					}
+				} else {
+					eg.addElement(clone);
+				}
+				whereClause = eg;
+			}
+		}
+	}
+
+	/**
+	 * Get the element group for the clause. if The element group is not set,
+	 * create and set it.
+	 * 
+	 * Public for ExprFactory use.
+	 * 
+	 * @return The element group.
+	 */
+	public ElementGroup getClause() {
+		Element e = whereClause;
+		if (e == null) {
+			e = new ElementGroup();
+			whereClause = e;
+		}
+		if (e instanceof ElementGroup) {
+			return (ElementGroup) e;
+		}
+
+		ElementGroup eg = new ElementGroup();
+		eg.addElement(e);
+		whereClause = eg;
+		return eg;
+	}
+
+	/**
+	 * Test that a triple is valid. Throws an IllegalArgumentException if the
+	 * triple is not valid.
+	 * 
+	 * @param t
+	 *            The trip to test.
+	 */
+	private static void testTriple(TriplePath t) {
+		// verify Triple is valid
+		boolean validSubject = t.getSubject().isURI() || t.getSubject().isBlank() || t.getSubject().isVariable()
+				|| t.getSubject().equals(Node.ANY);
+		boolean validPredicate;
+
+		if (t.isTriple()) {
+			validPredicate = t.getPredicate().isURI() || t.getPredicate().isVariable()
+					|| t.getPredicate().equals(Node.ANY);
+		} else {
+			validPredicate = t.getPath() != null;
+		}
+
+		boolean validObject = t.getObject().isURI() || t.getObject().isLiteral() || t.getObject().isBlank()
+				|| t.getObject().isVariable() || t.getObject().equals(Node.ANY);
+
+		if (!validSubject || !validPredicate || !validObject) {
+			StringBuilder sb = new StringBuilder();
+			if (!validSubject) {
+				sb.append(String.format("Subject (%s) must be a URI, blank, variable, or a wildcard. %n",
+						t.getSubject()));
+			}
+			if (!validPredicate) {
+				sb.append(String.format("Predicate (%s) must be a Path, URI , variable, or a wildcard. %n",
+						t.getPredicate()));
+			}
+			if (!validObject) {
+				sb.append(String.format("Object (%s) must be a URI, literal, blank, , variable, or a wildcard. %n",
+						t.getObject()));
+			}
+			if (!validSubject || !validPredicate) {
+				sb.append(String.format("Is a prefix missing?  Prefix must be defined before use. %n"));
+			}
+			throw new IllegalArgumentException(sb.toString());
+		}
+	}
+
+	/**
+	 * Add the triple path to the where clause
+	 * 
+	 * @param t
+	 *            The triple path to add.
+	 * @throws IllegalArgumentException
+	 *             If the triple path is not a valid triple path for a where
+	 *             clause.
+	 */
+	public void addWhere(TriplePath t) throws IllegalArgumentException {
+		testTriple(t);
+		ElementGroup eg = getClause();
+		List<Element> lst = eg.getElements();
+		if (lst.isEmpty()) {
+			ElementPathBlock epb = new ElementPathBlock();
+			epb.addTriple(t);
+			eg.addElement(epb);
+		} else {
+			Element e = lst.get(lst.size() - 1);
+			if (e instanceof ElementTriplesBlock && t.isTriple()) {
+				ElementTriplesBlock etb = (ElementTriplesBlock) e;
+				etb.addTriple(t.asTriple());
+			} else if (e instanceof ElementPathBlock) {
+				ElementPathBlock epb = (ElementPathBlock) e;
+				epb.addTriple(t);
+			} else {
+				ElementPathBlock etb = new ElementPathBlock();
+				etb.addTriple(t);
+				eg.addElement(etb);
+			}
+
+		}
+	}
+
+	/**
+	 * Add an optional triple to the where clause
+	 * 
+	 * @param t
+	 *            The triple path to add.
+	 * @throws IllegalArgumentException
+	 *             If the triple is not a valid triple for a where clause.
+	 */
+	public void addOptional(TriplePath t) throws IllegalArgumentException {
+		testTriple(t);
+		ElementPathBlock epb = new ElementPathBlock();
+		epb.addTriple(t);
+		ElementOptional opt = new ElementOptional(epb);
+		getClause().addElement(opt);
+	}
+
+	/**
+	 * Add the contents of a where handler as an optional statement.
+	 * 
+	 * @param whereHandler
+	 *            The where handler to use as the optional statement.
+	 */
+	public void addOptional(WhereHandler whereHandler) {
+		getClause().addElement(new ElementOptional(whereHandler.getClause()));
+	}
+
+	/**
+	 * Add an expression string as a filter.
+	 * 
+	 * @param expression
+	 *            The expression string to add.
+	 * @throws ParseException
+	 *             If the expression can not be parsed.
+	 */
+	public void addFilter(String expression) throws ParseException {
+		getClause().addElement(new ElementFilter(parseExpr(expression)));
+	}
+
+	private Expr parseExpr(String expression) {
+		Query query = new Query();
+		query.setPrefixMapping(prefixHandler.getPrefixes());
+		return ExprUtils.parse(query, expression, true);
+
+	}
+
+	/**
+	 * add an expression as a filter.
+	 * 
+	 * @param expr
+	 *            The expression to add.
+	 */
+	public void addFilter(Expr expr) {
+		getClause().addElement(new ElementFilter(expr));
+	}
+
+	/**
+	 * Add a subquery to the where clause.
+	 * 
+	 * @param subQuery
+	 *            The sub query to add.
+	 */
+	public void addSubQuery(AbstractQueryBuilder<?> subQuery) {
+		getClause().addElement(subQuery.asSubQuery());
+	}
+
+	/**
+	 * Add a union to the where clause.
+	 * 
+	 * @param subQuery
+	 *            The subquery to add as the union.
+	 */
+	public void addUnion(AbstractQueryBuilder<?> subQuery) {
+		ElementUnion union = null;
+		ElementGroup clause = getClause();
+		// if the last element is a union make sure we add to it.
+		if (!clause.isEmpty()) {
+			Element lastElement = clause.getElements().get(clause.getElements().size() - 1);
+			if (lastElement instanceof ElementUnion) {
+				union = (ElementUnion) lastElement;
+			} else {
+				// clauses is not empty and is not a union so it is the left
+				// side of the union.
+				union = new ElementUnion();
+				union.addElement(clause);
+				whereClause = union;
+			}
+		} else {
+			// add the union as the first element in the clause.
+			union = new ElementUnion();
+			clause.addElement(union);
+		}
+		// if there are projected vars then do a full blown subquery
+		// otherwise just add the clause.
+		if (subQuery instanceof SelectClause && ((SelectClause<?>) subQuery).getVars().size() > 0) {
+			union.addElement(subQuery.asSubQuery());
+		} else {
+			prefixHandler.addPrefixes(subQuery.getPrologHandler().getPrefixes());
+			union.addElement(subQuery.getWhereHandler().getClause());
+		}
+
+	}
+
+	/**
+	 * Add a graph to the where clause.
+	 * 
+	 * @param graph
+	 *            The name of the graph.
+	 * @param subQuery
+	 *            The where handler that defines the graph.
+	 */
+	public void addGraph(Node graph, WhereHandler subQuery) {
+		getClause().addElement(new ElementNamedGraph(graph, subQuery.getClause()));
+	}
+
+	/**
+	 * Add a binding to the where clause.
+	 * 
+	 * @param expr
+	 *            The expression to bind.
+	 * @param var
+	 *            The variable to bind it to.
+	 */
+	public void addBind(Expr expr, Var var) {
+		getClause().addElement(new ElementBind(var, expr));
+	}
+
+	/**
+	 * Add a binding to the where clause.
+	 * 
+	 * @param expression
+	 *            The expression to bind.
+	 * @param var
+	 *            The variable to bind it to.
+	 * @throws ParseException
+	 */
+	public void addBind(String expression, Var var) throws ParseException {
+		getClause().addElement(new ElementBind(var, parseExpr(expression)));
+	}
+
+	/**
+	 * replace the vars in the expressions with the nodes in the values map.
+	 * Vars not listed in the values map are not changed.
+	 * 
+	 * Will return null if the whereClause is null.
+	 * 
+	 * @param values
+	 *            the value map to use
+	 * @return A new Element instance with the values changed.
+	 */
+	public Element setVars(Map<Var, Node> values) {
+		if (values.isEmpty() || whereClause == null) {
+			return whereClause;
+		}
+		ElementRewriter r = new ElementRewriter(values);
+		whereClause.visit(r);
+		return r.getResult();
+
+	}
+	
+	@Override
+	public QuadHolder setValues(Map<Var, Node> values)
+	{
+		setVars( values );
+		return this;
+	}
+
+	/**
+	 * Create a list node from a list of objects as per RDF Collections.
+	 * 
+	 * http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#collections
+	 * 
+	 * @param objs
+	 *            the list of objects for the list.
+	 * @return the first blank node in the list.
+	 */
+	public Node list(Object... objs) {
+		Node retval = NodeFactory.createBlankNode();
+		Node lastObject = retval;
+		for (int i = 0; i < objs.length; i++) {
+			Node n = AbstractQueryBuilder.makeNode(objs[i], prefixHandler.getPrefixes());
+			addWhere(new TriplePath(new Triple(lastObject, RDF.first.asNode(), n)));
+			if (i + 1 < objs.length) {
+				Node nextObject = NodeFactory.createBlankNode();
+				addWhere(new TriplePath(new Triple(lastObject, RDF.rest.asNode(), nextObject)));
+				lastObject = nextObject;
+			} else {
+				addWhere(new TriplePath(new Triple(lastObject, RDF.rest.asNode(), RDF.nil.asNode())));
+			}
+
+		}
+
+		return retval;
+	}
+
+	/**
+	 * Add a minus operation to the where clause.
+	 * The prefixes will be updated with the prefixes from the abstract query builder.
+	 * 
+	 * @param qb the abstract builder that defines the data to subtract.
+	 */
+	public void addMinus(AbstractQueryBuilder<?> qb) {
+		prefixHandler.addPrefixes(qb.getPrologHandler().getPrefixes());
+		ElementGroup clause = getClause();
+		ElementMinus minus = new ElementMinus(qb.getWhereHandler().getClause());
+		clause.addElement(minus);
+	}
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/7d96286e/jena-extras/jena-querybuilder/src/test/java/Example10.java
----------------------------------------------------------------------
diff --git a/jena-extras/jena-querybuilder/src/test/java/Example10.java b/jena-extras/jena-querybuilder/src/test/java/Example10.java
new file mode 100644
index 0000000..7acbd7c
--- /dev/null
+++ b/jena-extras/jena-querybuilder/src/test/java/Example10.java
@@ -0,0 +1,104 @@
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.jena.datatypes.xsd.XSDDatatype;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.query.Dataset;
+import org.apache.jena.query.DatasetFactory;
+import org.apache.jena.rdf.model.Literal;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.rdf.model.ResourceFactory;
+import org.apache.jena.update.UpdateAction;
+import org.apache.jena.update.UpdateFactory;
+import org.apache.jena.update.UpdateRequest;
+import org.apache.jena.vocabulary.DCTypes;
+import org.apache.jena.vocabulary.DC_11;
+import org.junit.Test;
+
+public class Example10 {
+
+	/**
+	 * 	Example 10: 
+	 * 
+	 *  @see https://www.w3.org/TR/sparql11-update/#example_10
+	 */
+	@Test
+	public void example10()
+	{
+
+		Resource book1 = ResourceFactory.createResource( "http://example/book1" );
+		Resource book3 = ResourceFactory.createResource( "http://example/book3" );
+		Resource book4 = ResourceFactory.createResource( "http://example/book4" );
+		
+		Literal d1996 = ResourceFactory.createTypedLiteral("1996-01-01T00:00:00-02:00", XSDDatatype.XSDdateTime);
+		
+		Node graphName1 = NodeFactory.createURI("http://example/bookStore");
+		Node graphName2 = NodeFactory.createURI("http://example/bookStore2");
+		
+		Model m1 = ModelFactory.createDefaultModel();
+		m1.add( book1, DC_11.title, "Fundamentals of Compiler Design");
+		m1.add( book1, DC_11.date, d1996 );
+		m1.add( book1, DC_11.date, DCTypes.PhysicalObject );
+			
+		m1.add( book3, DC_11.title, "SPARQL 1.1 Tutorial" );
+		
+		Model m2 = ModelFactory.createDefaultModel();
+		m2.add( book4, DC_11.title, "SPARQL 1.1 Tutorial" );
+		
+		Dataset ds = DatasetFactory.create();
+		ds.addNamedModel(graphName1.getURI(), m1);
+		ds.addNamedModel(graphName2.getURI(), m2);
+	
+		String s = "PREFIX dc:  <http://purl.org/dc/elements/1.1/>\n"
+				+ "PREFIX dcmitype: <http://purl.org/dc/dcmitype/>\n"
+				+ "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\n"
+				+ "INSERT\n"
+				+ "  { GRAPH <http://example/bookStore2> { ?book ?p ?v } }\n"
+				+ "WHERE\n"
+				+ "  { GRAPH  <http://example/bookStore>\n"
+				+ "     { ?book dc:date ?date .\n"
+				+ "       FILTER ( ?date < \"2000-01-01T00:00:00-02:00\"^^xsd:dateTime )\n"
+				+ "       ?book ?p ?v\n"
+				+ "     }"
+				+ "  } ;\n\n"
+				+ "WITH <http://example/bookStore>\n"
+				+ "DELETE\n"
+				+ " { ?book ?p ?v }\n"
+				+ "WHERE\n"
+				+ " { ?book dc:date ?date ;\n"
+				+ "         dc:type dcmitype:PhysicalObject .\n"
+				+ "   FILTER ( ?date < \"2000-01-01T00:00:00-02:00\"^^xsd:dateTime )\n"
+				+ "   ?book ?p ?v\n"
+				+ " } ";
+		UpdateRequest req  = UpdateFactory.create(s);
+		
+		System.out.println( req );
+		
+		UpdateAction.execute( req, ds );
+		
+		m1 = ds.getNamedModel( graphName1.getURI());
+		assertEquals( "DELETE failed", 1, m1.listStatements().toList().size());
+
+		assertTrue( m1.contains( book3, DC_11.title, "SPARQL 1.1 Tutorial"));
+
+		
+		m2 = ds.getNamedModel( graphName2.getURI());
+		assertEquals( "Insert failed", 4, m2.listStatements().toList().size());
+
+
+		assertEquals( 3, m1.listStatements( book1, null, (RDFNode)null).toList().size());
+		assertTrue( m2.contains( book1, DC_11.title, "Fundamentals of Compiler Design"));
+		assertTrue( m2.contains( book1, DC_11.date, d1996 ));
+		assertTrue( m2.contains( book1, DC_11.date, DCTypes.PhysicalObject ));
+		
+		assertEquals( 1, m1.listStatements( book4, null, (RDFNode)null).toList().size());
+		assertTrue( m1.contains( book4, DC_11.title, "SPARQL 1.1 Tutorial"));
+		
+	}
+}