You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by th...@apache.org on 2013/06/27 10:39:08 UTC

[08/11] DELTASPIKE-60 Data module initial import

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilder.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilder.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilder.java
new file mode 100644
index 0000000..5743ca3
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilder.java
@@ -0,0 +1,121 @@
+/*
+ * 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.deltaspike.data.impl.builder;
+
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.List;
+
+import javax.persistence.LockModeType;
+import javax.persistence.Query;
+import javax.persistence.QueryHint;
+
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.param.Parameters;
+
+/**
+ * Query builder factory. Delegates to concrete implementations.
+ *
+ * @author thomashug
+ */
+public abstract class QueryBuilder
+{
+
+    public static final String QUERY_SELECT = "select e from {0} e";
+    public static final String QUERY_COUNT = "select count(e) from {0} e";
+    public static final String ENTITY_NAME = "e";
+
+    public static String selectQuery(String entityName)
+    {
+        return MessageFormat.format(QUERY_SELECT, entityName);
+    }
+
+    public static String countQuery(String entityName)
+    {
+        return MessageFormat.format(QUERY_COUNT, entityName);
+    }
+
+    public abstract Object execute(CdiQueryInvocationContext ctx);
+
+    protected boolean returnsList(Method method)
+    {
+        return method.getReturnType().isAssignableFrom(List.class);
+    }
+
+    protected LockModeType extractLockMode(Method method)
+    {
+        Class<org.apache.deltaspike.data.api.Query> query = org.apache.deltaspike.data.api.Query.class;
+        if (method.isAnnotationPresent(query) &&
+                method.getAnnotation(query).lock() != LockModeType.NONE)
+        {
+            return method.getAnnotation(query).lock();
+        }
+        return null;
+    }
+
+    protected boolean hasLockMode(Method method)
+    {
+        return extractLockMode(method) != null;
+    }
+
+    protected QueryHint[] extractQueryHints(Method method)
+    {
+        Class<org.apache.deltaspike.data.api.Query> query = org.apache.deltaspike.data.api.Query.class;
+        if (method.isAnnotationPresent(query) &&
+                method.getAnnotation(query).hints().length > 0)
+        {
+            return method.getAnnotation(query).hints();
+        }
+        return null;
+    }
+
+    protected boolean hasQueryHints(Method method)
+    {
+        return extractQueryHints(method) != null;
+    }
+
+    protected Query applyRestrictions(CdiQueryInvocationContext context, Query query)
+    {
+        Parameters params = context.getParams();
+        Method method = context.getMethod();
+        if (params.hasSizeRestriction())
+        {
+            query.setMaxResults(params.getSizeRestriciton());
+        }
+        if (params.hasFirstResult())
+        {
+            query.setFirstResult(params.getFirstResult());
+        }
+        if (hasLockMode(method))
+        {
+            query.setLockMode(extractLockMode(method));
+        }
+        if (hasQueryHints(method))
+        {
+            QueryHint[] hints = extractQueryHints(method);
+            for (QueryHint hint : hints)
+            {
+                query.setHint(hint.name(), hint.value());
+            }
+        }
+        query = context.applyJpaQueryPostProcessors(query);
+        return query;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderContext.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderContext.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderContext.java
new file mode 100644
index 0000000..c4681a4
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderContext.java
@@ -0,0 +1,56 @@
+/*
+ * 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.deltaspike.data.impl.builder;
+
+/**
+ * @author thomashug
+ */
+public class QueryBuilderContext
+{
+
+    private final StringBuilder builder;
+    private int counter = 1;
+
+    public QueryBuilderContext()
+    {
+        this.builder = new StringBuilder();
+    }
+
+    public int increment()
+    {
+        return counter++;
+    }
+
+    public QueryBuilderContext append(String string)
+    {
+        builder.append(string);
+        return this;
+    }
+
+    public String resultString()
+    {
+        return builder.toString();
+    }
+
+    public int getCounter()
+    {
+        return counter;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderFactory.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderFactory.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderFactory.java
new file mode 100644
index 0000000..b37c9b8
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryBuilderFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.deltaspike.data.impl.builder;
+
+import java.io.Serializable;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+
+import org.apache.deltaspike.data.api.QueryResult;
+import org.apache.deltaspike.data.impl.meta.RepositoryMethod;
+import org.apache.deltaspike.data.impl.meta.QueryInvocationLiteral;
+
+public class QueryBuilderFactory implements Serializable
+{
+
+    private static final long serialVersionUID = 1L;
+
+    @Inject
+    @Any
+    private Instance<QueryBuilder> queryBuilder;
+
+    public QueryBuilder build(RepositoryMethod method)
+    {
+        QueryBuilder builder = queryBuilder.select(new QueryInvocationLiteral(method.getMethodType())).get();
+        if (method.returns(QueryResult.class))
+        {
+            return new WrappedQueryBuilder(builder);
+        }
+        return builder;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryOperator.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryOperator.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryOperator.java
new file mode 100644
index 0000000..b4b3595
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/QueryOperator.java
@@ -0,0 +1,71 @@
+/*
+ * 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.deltaspike.data.impl.builder;
+
+/**
+ * Comparison options for queries.
+ *
+ * @author thomashug
+ */
+public enum QueryOperator
+{
+
+    LessThan("LessThan", "{0} < {1}"),
+    LessThanEquals("LessThanEquals", "{0} <= {1}"),
+    GreaterThan("GreaterThan", "{0} > {1}"),
+    GreaterThanEquals("GreaterThanEquals", "{0} >= {1}"),
+    Like("Like", "{0} like {1}"),
+    NotEqual("NotEqual", "{0} <> {1}"),
+    Equal("Equal", "{0} = {1}"),
+    Between("Between", "{0} between {1} and {2}", 2),
+    IsNotNull("IsNotNull", "{0} IS NOT NULL", 0),
+    IsNull("IsNull", "{0} IS NULL", 0);
+
+    private final String expression;
+    private final String jpql;
+    private final int paramNum;
+
+    private QueryOperator(String expression, String jpql)
+    {
+        this(expression, jpql, 1);
+    }
+
+    private QueryOperator(String expression, String jpql, int paramNum)
+    {
+        this.expression = expression;
+        this.jpql = jpql;
+        this.paramNum = paramNum;
+    }
+
+    public String getExpression()
+    {
+        return expression;
+    }
+
+    public String getJpql()
+    {
+        return jpql;
+    }
+
+    public int getParamNum()
+    {
+        return paramNum;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/WrappedQueryBuilder.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/WrappedQueryBuilder.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/WrappedQueryBuilder.java
new file mode 100644
index 0000000..8cb4147
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/WrappedQueryBuilder.java
@@ -0,0 +1,41 @@
+/*
+ * 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.deltaspike.data.impl.builder;
+
+import org.apache.deltaspike.data.impl.builder.result.DefaultQueryResult;
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+
+public class WrappedQueryBuilder extends QueryBuilder
+{
+
+    private final QueryBuilder delegate;
+
+    public WrappedQueryBuilder(QueryBuilder delegate)
+    {
+        this.delegate = delegate;
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public Object execute(CdiQueryInvocationContext ctx)
+    {
+        return new DefaultQueryResult(delegate, ctx);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/AndQueryPart.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/AndQueryPart.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/AndQueryPart.java
new file mode 100644
index 0000000..7dfcb97
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/AndQueryPart.java
@@ -0,0 +1,54 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+import org.apache.deltaspike.data.impl.builder.QueryBuilderContext;
+import org.apache.deltaspike.data.impl.meta.RepositoryComponent;
+
+/**
+ *
+ * @author thomashug
+ */
+class AndQueryPart extends ConnectingQueryPart
+{
+
+    public AndQueryPart(boolean first)
+    {
+        super(first);
+    }
+
+    @Override
+    protected QueryPart build(String queryPart, String method, RepositoryComponent repo)
+    {
+        children.add(new PropertyQueryPart().build(queryPart, method, repo));
+        return this;
+    }
+
+    @Override
+    protected QueryPart buildQuery(QueryBuilderContext ctx)
+    {
+        if (!first)
+        {
+            ctx.append(" and ");
+        }
+        buildQueryForChildren(ctx);
+        return this;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/BasePropertyQueryPart.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/BasePropertyQueryPart.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/BasePropertyQueryPart.java
new file mode 100644
index 0000000..13d2ac1
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/BasePropertyQueryPart.java
@@ -0,0 +1,62 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+import org.apache.deltaspike.data.impl.builder.MethodExpressionException;
+import org.apache.deltaspike.data.impl.meta.RepositoryComponent;
+import org.apache.deltaspike.data.impl.property.Property;
+import org.apache.deltaspike.data.impl.property.query.NamedPropertyCriteria;
+import org.apache.deltaspike.data.impl.property.query.PropertyQueries;
+import org.apache.deltaspike.data.impl.property.query.PropertyQuery;
+
+abstract class BasePropertyQueryPart extends QueryPart
+{
+
+    static final String SEPARATOR = "_";
+
+    void validate(String name, String method, RepositoryComponent repo)
+    {
+        Class<?> current = repo.getEntityClass();
+        if (name == null)
+        {
+            throw new MethodExpressionException(null, repo.getRepositoryClass(), method);
+        }
+        for (String property : name.split(SEPARATOR))
+        {
+            PropertyQuery<?> query = PropertyQueries.createQuery(current)
+                    .addCriteria(new NamedPropertyCriteria(property));
+            Property<?> result = query.getFirstResult();
+            if (result == null)
+            {
+                throw new MethodExpressionException(property, repo.getRepositoryClass(), method);
+            }
+            current = result.getJavaClass();
+        }
+    }
+
+    String rewriteSeparator(String name)
+    {
+        if (name.contains("_"))
+        {
+            return name.replaceAll(SEPARATOR, ".");
+        }
+        return name;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/ConnectingQueryPart.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/ConnectingQueryPart.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/ConnectingQueryPart.java
new file mode 100644
index 0000000..6752bc5
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/ConnectingQueryPart.java
@@ -0,0 +1,40 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+/**
+ *
+ * @author thomashug
+ */
+abstract class ConnectingQueryPart extends QueryPart
+{
+
+    protected final boolean first;
+
+    public ConnectingQueryPart(boolean first)
+    {
+        this.first = first;
+    }
+
+    public boolean isFirst()
+    {
+        return first;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrQueryPart.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrQueryPart.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrQueryPart.java
new file mode 100644
index 0000000..3873062
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrQueryPart.java
@@ -0,0 +1,62 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+import static org.apache.deltaspike.data.impl.util.QueryUtils.splitByKeyword;
+
+import org.apache.deltaspike.data.impl.builder.QueryBuilderContext;
+import org.apache.deltaspike.data.impl.meta.RepositoryComponent;
+
+/**
+ * @author thomashug
+ */
+class OrQueryPart extends ConnectingQueryPart
+{
+
+    public OrQueryPart(boolean first)
+    {
+        super(first);
+    }
+
+    @Override
+    protected QueryPart build(String queryPart, String method, RepositoryComponent repo)
+    {
+        String[] andParts = splitByKeyword(queryPart, "And");
+        boolean first = true;
+        for (String and : andParts)
+        {
+            AndQueryPart andPart = new AndQueryPart(first);
+            first = false;
+            children.add(andPart.build(and, method, repo));
+        }
+        return this;
+    }
+
+    @Override
+    protected QueryPart buildQuery(QueryBuilderContext ctx)
+    {
+        if (!first)
+        {
+            ctx.append(" or ");
+        }
+        buildQueryForChildren(ctx);
+        return this;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrderByQueryPart.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrderByQueryPart.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrderByQueryPart.java
new file mode 100644
index 0000000..9e87b8f
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/OrderByQueryPart.java
@@ -0,0 +1,154 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+import static org.apache.deltaspike.data.impl.util.QueryUtils.isNotEmpty;
+import static org.apache.deltaspike.data.impl.util.QueryUtils.splitByKeyword;
+import static org.apache.deltaspike.data.impl.util.QueryUtils.uncapitalize;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.deltaspike.data.impl.builder.QueryBuilder;
+import org.apache.deltaspike.data.impl.builder.QueryBuilderContext;
+import org.apache.deltaspike.data.impl.meta.RepositoryComponent;
+
+
+public class OrderByQueryPart extends BasePropertyQueryPart
+{
+
+    private static final String KEYWORD_ASC = "Asc";
+    private static final String KEYWORD_DESC = "Desc";
+
+    private final List<OrderByQueryAttribute> attributes = new LinkedList<OrderByQueryAttribute>();
+
+    @Override
+    protected QueryPart build(String queryPart, String method, RepositoryComponent repo)
+    {
+        Set<String> collect = new TreeSet<String>();
+        List<String> ascSplit = new LinkedList<String>();
+        split(queryPart, KEYWORD_ASC, ascSplit);
+        for (String ascPart : ascSplit)
+        {
+            split(ascPart, KEYWORD_DESC, collect);
+        }
+        for (String part : collect)
+        {
+            Direction direction = Direction.fromQueryPart(part);
+            String attribute = direction.attribute(part);
+            validate(attribute, method, repo);
+            attributes.add(new OrderByQueryAttribute(attribute, direction));
+        }
+        return this;
+    }
+
+    @Override
+    protected QueryPart buildQuery(QueryBuilderContext ctx)
+    {
+        ctx.append(" order by ");
+        for (Iterator<OrderByQueryAttribute> it = attributes.iterator(); it.hasNext();)
+        {
+            it.next().buildQuery(ctx);
+            if (it.hasNext())
+            {
+                ctx.append(", ");
+            }
+        }
+        return this;
+    }
+
+    private void split(String queryPart, String keyword, Collection<String> result)
+    {
+        for (String part : splitByKeyword(queryPart, keyword))
+        {
+            String attribute = !part.endsWith(KEYWORD_DESC) && !part.endsWith(KEYWORD_ASC) ? part + keyword : part;
+            result.add(attribute);
+        }
+    }
+
+    private class OrderByQueryAttribute
+    {
+
+        private final String attribute;
+        private final Direction direction;
+
+        public OrderByQueryAttribute(String attribute, Direction direction)
+        {
+            this.attribute = attribute;
+            this.direction = direction;
+        }
+
+        protected void buildQuery(QueryBuilderContext ctx)
+        {
+            String entityPrefix = QueryBuilder.ENTITY_NAME + ".";
+            ctx.append(entityPrefix).append(rewriteSeparator(attribute))
+                    .append(direction.queryDirection());
+        }
+    }
+
+    private static enum Direction
+    {
+        ASC(KEYWORD_ASC),
+        DESC(KEYWORD_DESC),
+        DEFAULT("");
+
+        private final String postfix;
+
+        private Direction(String postfix)
+        {
+            this.postfix = postfix;
+        }
+
+        public boolean endsWith(String queryPart)
+        {
+            return isNotEmpty(postfix) ? queryPart.endsWith(postfix) : false;
+        }
+
+        public String attribute(String queryPart)
+        {
+            String attribute = isNotEmpty(postfix) ?
+                    queryPart.substring(0, queryPart.indexOf(postfix)) :
+                    queryPart;
+            return uncapitalize(attribute);
+        }
+
+        public String queryDirection()
+        {
+            return isNotEmpty(postfix) ? " " + postfix.toLowerCase() : "";
+        }
+
+        public static Direction fromQueryPart(String queryPart)
+        {
+            for (Direction dir : values())
+            {
+                if (dir.endsWith(queryPart))
+                {
+                    return dir;
+                }
+            }
+            return DEFAULT;
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/PropertyQueryPart.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/PropertyQueryPart.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/PropertyQueryPart.java
new file mode 100644
index 0000000..b6aac30
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/PropertyQueryPart.java
@@ -0,0 +1,72 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+import static org.apache.deltaspike.data.impl.util.QueryUtils.uncapitalize;
+
+import java.text.MessageFormat;
+
+import org.apache.deltaspike.data.impl.builder.QueryBuilder;
+import org.apache.deltaspike.data.impl.builder.QueryBuilderContext;
+import org.apache.deltaspike.data.impl.builder.QueryOperator;
+import org.apache.deltaspike.data.impl.meta.RepositoryComponent;
+
+/**
+ *
+ * @author thomashug
+ */
+class PropertyQueryPart extends BasePropertyQueryPart
+{
+
+    private String name;
+    private QueryOperator comparator;
+
+    @Override
+    protected QueryPart build(String queryPart, String method, RepositoryComponent repo)
+    {
+        comparator = QueryOperator.Equal;
+        name = uncapitalize(queryPart);
+        for (QueryOperator comp : QueryOperator.values())
+        {
+            if (queryPart.endsWith(comp.getExpression()))
+            {
+                comparator = comp;
+                name = uncapitalize(queryPart.substring(0, queryPart.indexOf(comp.getExpression())));
+                break;
+            }
+        }
+        validate(name, method, repo);
+        name = rewriteSeparator(name);
+        return this;
+    }
+
+    @Override
+    protected QueryPart buildQuery(QueryBuilderContext ctx)
+    {
+        String[] args = new String[comparator.getParamNum() + 1];
+        args[0] = QueryBuilder.ENTITY_NAME + "." + name;
+        for (int i = 1; i < args.length; i++)
+        {
+            args[i] = "?" + ctx.increment();
+        }
+        ctx.append(MessageFormat.format(comparator.getJpql(), (Object[]) args));
+        return this;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryPart.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryPart.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryPart.java
new file mode 100644
index 0000000..d51ec50
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryPart.java
@@ -0,0 +1,64 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.deltaspike.data.impl.builder.QueryBuilderContext;
+import org.apache.deltaspike.data.impl.meta.RepositoryComponent;
+
+/**
+ * @author thomashug
+ */
+public abstract class QueryPart
+{
+
+    protected List<QueryPart> children = new LinkedList<QueryPart>();
+
+    protected abstract QueryPart build(String queryPart, String method, RepositoryComponent repo);
+
+    protected abstract QueryPart buildQuery(QueryBuilderContext ctx);
+
+    protected void buildQueryForChildren(QueryBuilderContext ctx)
+    {
+        for (QueryPart child : children)
+        {
+            child.buildQuery(ctx);
+        }
+    }
+
+    protected boolean hasChildren(Set<Class<? extends QueryPart>> excluded)
+    {
+        if (children == null || children.isEmpty())
+        {
+            return false;
+        }
+        for (QueryPart part : children)
+        {
+            if (!excluded.contains(part.getClass()))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryRoot.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryRoot.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryRoot.java
new file mode 100644
index 0000000..5adb0ad
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/part/QueryRoot.java
@@ -0,0 +1,138 @@
+/*
+ * 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.deltaspike.data.impl.builder.part;
+
+import static org.apache.deltaspike.data.impl.util.QueryUtils.splitByKeyword;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.deltaspike.data.impl.builder.MethodExpressionException;
+import org.apache.deltaspike.data.impl.builder.QueryBuilder;
+import org.apache.deltaspike.data.impl.builder.QueryBuilderContext;
+import org.apache.deltaspike.data.impl.meta.RepositoryComponent;
+
+/**
+ * Root of the query tree. Also the only exposed class in the package.
+ *
+ * @author thomashug
+ */
+public class QueryRoot extends QueryPart
+{
+
+    public static final QueryRoot UNKNOWN_ROOT = new QueryRoot("null-object", "");
+
+    private static final Logger log = Logger.getLogger(QueryRoot.class.getName());
+
+    private final String entityName;
+    private final String queryPrefix;
+
+    private String jpqlQuery;
+
+    protected QueryRoot(String entityName, String queryPrefix)
+    {
+        this.entityName = entityName;
+        this.queryPrefix = queryPrefix;
+    }
+
+    public static QueryRoot create(String method, RepositoryComponent repo)
+    {
+        QueryRoot root = new QueryRoot(repo.getEntityName(), repo.getMethodPrefix());
+        root.build(method, method, repo);
+        root.createJpql();
+        return root;
+    }
+
+    public String getJpqlQuery()
+    {
+        return jpqlQuery;
+    }
+
+    @Override
+    protected QueryPart build(String queryPart, String method, RepositoryComponent repo)
+    {
+        String[] orderByParts = splitByKeyword(queryPart, "OrderBy");
+        if (hasQueryConditions(orderByParts))
+        {
+            String[] orParts = splitByKeyword(removePrefix(orderByParts[0]), "Or");
+            boolean first = true;
+            for (String or : orParts)
+            {
+                OrQueryPart orPart = new OrQueryPart(first);
+                first = false;
+                children.add(orPart.build(or, method, repo));
+            }
+        }
+        if (orderByParts.length > 1)
+        {
+            OrderByQueryPart orderByPart = new OrderByQueryPart();
+            children.add(orderByPart.build(orderByParts[1], method, repo));
+        }
+        if (children.isEmpty())
+        {
+            throw new MethodExpressionException(repo.getRepositoryClass(), method);
+        }
+        return this;
+    }
+
+    @Override
+    protected QueryPart buildQuery(QueryBuilderContext ctx)
+    {
+        ctx.append(QueryBuilder.selectQuery(entityName));
+        if (hasChildren(excludedForWhereCheck()))
+        {
+            ctx.append(" where ");
+        }
+        buildQueryForChildren(ctx);
+        return this;
+    }
+
+    protected String createJpql()
+    {
+        QueryBuilderContext ctx = new QueryBuilderContext();
+        buildQuery(ctx);
+        jpqlQuery = ctx.resultString();
+        log.log(Level.FINER, "createJpql: Query is {0}", jpqlQuery);
+        return jpqlQuery;
+    }
+
+    private Set<Class<? extends QueryPart>> excludedForWhereCheck()
+    {
+        Set<Class<? extends QueryPart>> excluded = new HashSet<Class<? extends QueryPart>>();
+        excluded.add(OrderByQueryPart.class);
+        return excluded;
+    }
+
+    private boolean hasQueryConditions(String[] orderByParts)
+    {
+        return !queryPrefix.equals(orderByParts[0]);
+    }
+
+    private String removePrefix(String queryPart)
+    {
+        if (queryPart.startsWith(queryPrefix))
+        {
+            return queryPart.substring(queryPrefix.length());
+        }
+        return queryPart;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/CountQueryPostProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/CountQueryPostProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/CountQueryPostProcessor.java
new file mode 100644
index 0000000..6659776
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/CountQueryPostProcessor.java
@@ -0,0 +1,124 @@
+/*
+ * 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.deltaspike.data.impl.builder.postprocessor;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.handler.JpaQueryPostProcessor;
+import org.apache.deltaspike.data.impl.param.Parameters;
+import org.apache.deltaspike.data.impl.util.QueryUtils;
+import org.apache.deltaspike.data.impl.util.jpa.QueryStringExtractorFactory;
+
+public class CountQueryPostProcessor implements JpaQueryPostProcessor
+{
+
+    private static final Logger log = Logger.getLogger(CountQueryPostProcessor.class.getName());
+
+    private final QueryStringExtractorFactory factory = new QueryStringExtractorFactory();
+
+    @Override
+    public Query postProcess(CdiQueryInvocationContext context, Query query)
+    {
+        String queryString = getQueryString(context, query);
+        QueryExtraction extract = new QueryExtraction(queryString);
+        String count = extract.rewriteToCount();
+        log.log(Level.FINER, "Rewrote query {0} to {1}", new Object[] { queryString, count });
+        Query result = context.getEntityManager().createQuery(count);
+        Parameters params = context.getParams();
+        params.applyTo(result);
+        return result;
+    }
+
+    private String getQueryString(CdiQueryInvocationContext context, Query query)
+    {
+        if (QueryUtils.isNotEmpty(context.getQueryString()))
+        {
+            return context.getQueryString();
+        }
+        return factory.select(query).extractFrom(query);
+    }
+
+    private static class QueryExtraction
+    {
+
+        private String select;
+        private String from;
+        private String where;
+
+        private String entityName;
+        private final String query;
+
+        public QueryExtraction(String query)
+        {
+            this.query = query;
+        }
+
+        public String rewriteToCount()
+        {
+            splitQuery();
+            extractEntityName();
+            return rewrite();
+        }
+
+        private String rewrite()
+        {
+            return "select count(" + (select != null ? select : entityName) + ") " + from + where;
+        }
+
+        private void extractEntityName()
+        {
+            String[] split = from.split(" ");
+            if (split.length > 1)
+            {
+                entityName = split[split.length - 1];
+            }
+            else
+            {
+                entityName = "*";
+            }
+        }
+
+        private void splitQuery()
+        {
+            String lower = query.toLowerCase();
+            int selectIndex = lower.indexOf("select");
+            int fromIndex = lower.indexOf("from");
+            int whereIndex = lower.indexOf("where");
+            if (selectIndex >= 0)
+            {
+                select = query.substring("select".length(), fromIndex);
+            }
+            if (whereIndex >= 0)
+            {
+                from = query.substring(fromIndex, whereIndex);
+                where = query.substring(whereIndex);
+            }
+            else
+            {
+                from = query.substring(fromIndex);
+            }
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FirstResultPostProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FirstResultPostProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FirstResultPostProcessor.java
new file mode 100644
index 0000000..3733a57
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FirstResultPostProcessor.java
@@ -0,0 +1,43 @@
+/*
+ * 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.deltaspike.data.impl.builder.postprocessor;
+
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.handler.JpaQueryPostProcessor;
+
+public class FirstResultPostProcessor implements JpaQueryPostProcessor
+{
+
+    private final int startPosition;
+
+    public FirstResultPostProcessor(int startPosition)
+    {
+        this.startPosition = startPosition;
+    }
+
+    @Override
+    public Query postProcess(CdiQueryInvocationContext context, Query query)
+    {
+        query.setFirstResult(startPosition);
+        return query;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FlushModePostProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FlushModePostProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FlushModePostProcessor.java
new file mode 100644
index 0000000..a97e8b4
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/FlushModePostProcessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.deltaspike.data.impl.builder.postprocessor;
+
+import javax.persistence.FlushModeType;
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.handler.JpaQueryPostProcessor;
+
+public class FlushModePostProcessor implements JpaQueryPostProcessor
+{
+
+    private final FlushModeType flushMode;
+
+    public FlushModePostProcessor(FlushModeType flushMode)
+    {
+        this.flushMode = flushMode;
+    }
+
+    @Override
+    public Query postProcess(CdiQueryInvocationContext context, Query query)
+    {
+        query.setFlushMode(flushMode);
+        return query;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/HintPostProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/HintPostProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/HintPostProcessor.java
new file mode 100644
index 0000000..beb7722
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/HintPostProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.deltaspike.data.impl.builder.postprocessor;
+
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.handler.JpaQueryPostProcessor;
+
+public class HintPostProcessor implements JpaQueryPostProcessor
+{
+
+    private final String hintName;
+    private final Object hintValue;
+
+    public HintPostProcessor(String hintName, Object hintValue)
+    {
+        this.hintName = hintName;
+        this.hintValue = hintValue;
+    }
+
+    @Override
+    public Query postProcess(CdiQueryInvocationContext context, Query query)
+    {
+        query.setHint(hintName, hintValue);
+        return query;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/LockModePostProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/LockModePostProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/LockModePostProcessor.java
new file mode 100644
index 0000000..6c21f8c
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/LockModePostProcessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.deltaspike.data.impl.builder.postprocessor;
+
+import javax.persistence.LockModeType;
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.handler.JpaQueryPostProcessor;
+
+public class LockModePostProcessor implements JpaQueryPostProcessor
+{
+
+    private final LockModeType lockMode;
+
+    public LockModePostProcessor(LockModeType lockMode)
+    {
+        this.lockMode = lockMode;
+    }
+
+    @Override
+    public Query postProcess(CdiQueryInvocationContext context, Query query)
+    {
+        query.setLockMode(lockMode);
+        return query;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/MaxResultPostProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/MaxResultPostProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/MaxResultPostProcessor.java
new file mode 100644
index 0000000..d97f618
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/MaxResultPostProcessor.java
@@ -0,0 +1,43 @@
+/*
+ * 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.deltaspike.data.impl.builder.postprocessor;
+
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.handler.JpaQueryPostProcessor;
+
+public class MaxResultPostProcessor implements JpaQueryPostProcessor
+{
+
+    private final int max;
+
+    public MaxResultPostProcessor(int max)
+    {
+        this.max = max;
+    }
+
+    @Override
+    public Query postProcess(CdiQueryInvocationContext context, Query query)
+    {
+        query.setMaxResults(max);
+        return query;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/OrderByQueryStringPostProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/OrderByQueryStringPostProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/OrderByQueryStringPostProcessor.java
new file mode 100644
index 0000000..cb9f046
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/postprocessor/OrderByQueryStringPostProcessor.java
@@ -0,0 +1,80 @@
+/*
+ * 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.deltaspike.data.impl.builder.postprocessor;
+
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.apache.deltaspike.data.impl.builder.OrderDirection;
+import org.apache.deltaspike.data.impl.builder.QueryBuilder;
+import org.apache.deltaspike.data.impl.handler.QueryStringPostProcessor;
+
+public class OrderByQueryStringPostProcessor implements QueryStringPostProcessor
+{
+
+    private static final String ORDER_BY = " order by ";
+
+    private final String attribute;
+    private OrderDirection direction;
+
+    public OrderByQueryStringPostProcessor(SingularAttribute<?, ?> attribute, OrderDirection direction)
+    {
+        this.attribute = attribute.getName();
+        this.direction = direction;
+    }
+
+    public OrderByQueryStringPostProcessor(String attribute, OrderDirection direction)
+    {
+        this.attribute = attribute;
+        this.direction = direction;
+    }
+
+    @Override
+    public String postProcess(String queryString)
+    {
+        StringBuilder builder = new StringBuilder(queryString);
+        if (queryString.contains(ORDER_BY))
+        {
+            builder.append(",");
+        }
+        else
+        {
+            builder.append(ORDER_BY);
+        }
+        return builder.append(QueryBuilder.ENTITY_NAME)
+                .append(".").append(attribute)
+                .append(" ").append(direction)
+                .toString();
+    }
+
+    public boolean matches(SingularAttribute<?, ?> attribute)
+    {
+        return matches(attribute.getName());
+    }
+
+    public boolean matches(String attribute)
+    {
+        return this.attribute.equals(attribute);
+    }
+
+    public void changeDirection()
+    {
+        direction = direction.change();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/DefaultQueryResult.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/DefaultQueryResult.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/DefaultQueryResult.java
new file mode 100644
index 0000000..c6b7c72
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/DefaultQueryResult.java
@@ -0,0 +1,284 @@
+/*
+ * 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.deltaspike.data.impl.builder.result;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.persistence.FlushModeType;
+import javax.persistence.LockModeType;
+import javax.persistence.Query;
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.apache.deltaspike.data.api.QueryResult;
+import org.apache.deltaspike.data.impl.builder.OrderDirection;
+import org.apache.deltaspike.data.impl.builder.QueryBuilder;
+import org.apache.deltaspike.data.impl.builder.postprocessor.CountQueryPostProcessor;
+import org.apache.deltaspike.data.impl.builder.postprocessor.FirstResultPostProcessor;
+import org.apache.deltaspike.data.impl.builder.postprocessor.FlushModePostProcessor;
+import org.apache.deltaspike.data.impl.builder.postprocessor.HintPostProcessor;
+import org.apache.deltaspike.data.impl.builder.postprocessor.LockModePostProcessor;
+import org.apache.deltaspike.data.impl.builder.postprocessor.MaxResultPostProcessor;
+import org.apache.deltaspike.data.impl.builder.postprocessor.OrderByQueryStringPostProcessor;
+import org.apache.deltaspike.data.impl.handler.CdiQueryInvocationContext;
+import org.apache.deltaspike.data.impl.handler.QueryStringPostProcessor;
+
+public class DefaultQueryResult<T> implements QueryResult<T>
+{
+
+    private final QueryBuilder builder;
+    private final CdiQueryInvocationContext context;
+
+    private int page = 0;
+    private int pageSize = 10;
+
+    public DefaultQueryResult(QueryBuilder builder, CdiQueryInvocationContext context)
+    {
+        this.builder = builder;
+        this.context = context;
+    }
+
+    @Override
+    public <X> QueryResult<T> orderAsc(SingularAttribute<T, X> attribute)
+    {
+        context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.ASC));
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> orderAsc(String attribute)
+    {
+        context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.ASC));
+        return this;
+    }
+
+    @Override
+    public <X> QueryResult<T> orderDesc(SingularAttribute<T, X> attribute)
+    {
+        context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.DESC));
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> orderDesc(String attribute)
+    {
+        context.addQueryStringPostProcessor(new OrderByQueryStringPostProcessor(attribute, OrderDirection.DESC));
+        return this;
+    }
+
+    @Override
+    public <X> QueryResult<T> changeOrder(final SingularAttribute<T, X> attribute)
+    {
+        changeOrder(new ChangeOrder()
+        {
+            @Override
+            public boolean matches(OrderByQueryStringPostProcessor orderBy)
+            {
+                return orderBy.matches(attribute);
+            }
+
+            @Override
+            public void addDefault()
+            {
+                orderAsc(attribute);
+            }
+        });
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> changeOrder(final String attribute)
+    {
+        changeOrder(new ChangeOrder()
+        {
+            @Override
+            public boolean matches(OrderByQueryStringPostProcessor orderBy)
+            {
+                return orderBy.matches(attribute);
+            }
+
+            @Override
+            public void addDefault()
+            {
+                orderAsc(attribute);
+            }
+        });
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> clearOrder()
+    {
+        for (Iterator<QueryStringPostProcessor> it = context.getQueryStringPostProcessors().iterator(); it.hasNext();)
+        {
+            if (it.next() instanceof OrderByQueryStringPostProcessor)
+            {
+                it.remove();
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> maxResults(int max)
+    {
+        context.addJpaQueryPostProcessor(new MaxResultPostProcessor(max));
+        pageSize = max;
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> firstResult(int first)
+    {
+        context.addJpaQueryPostProcessor(new FirstResultPostProcessor(first));
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> lockMode(LockModeType lockMode)
+    {
+        context.addJpaQueryPostProcessor(new LockModePostProcessor(lockMode));
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> flushMode(FlushModeType flushMode)
+    {
+        context.addJpaQueryPostProcessor(new FlushModePostProcessor(flushMode));
+        return this;
+    }
+
+    @Override
+    public QueryResult<T> hint(String hint, Object value)
+    {
+        context.addJpaQueryPostProcessor(new HintPostProcessor(hint, value));
+        return this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<T> getResultList()
+    {
+        return ((Query) builder.execute(context)).getResultList();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T getSingleResult()
+    {
+        return (T) ((Query) builder.execute(context)).getSingleResult();
+    }
+
+    @Override
+    public long count()
+    {
+        CountQueryPostProcessor counter = new CountQueryPostProcessor();
+        context.addJpaQueryPostProcessor(counter);
+        try
+        {
+            Long result = (Long) ((Query) builder.execute(context)).getSingleResult();
+            return result.intValue();
+        }
+        catch (RuntimeException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+        finally
+        {
+            context.removeJpaQueryPostProcessor(counter);
+        }
+    }
+
+    @Override
+    public QueryResult<T> withPageSize(int pageSize)
+    {
+        return maxResults(pageSize);
+    }
+
+    @Override
+    public QueryResult<T> toPage(int page)
+    {
+        this.page = page;
+        return firstResult(pageSize * page);
+    }
+
+    @Override
+    public QueryResult<T> nextPage()
+    {
+        page = page + 1;
+        return firstResult(pageSize * page);
+    }
+
+    @Override
+    public QueryResult<T> previousPage()
+    {
+        page = page > 0 ? page - 1 : page;
+        return firstResult(pageSize * page);
+    }
+
+    @Override
+    public int countPages()
+    {
+        return (int) Math.ceil((double) count() / pageSize);
+    }
+
+    @Override
+    public int currentPage()
+    {
+        return page;
+    }
+
+    @Override
+    public int pageSize()
+    {
+        return pageSize;
+    }
+
+    private <X> QueryResult<T> changeOrder(ChangeOrder changeOrder)
+    {
+        for (QueryStringPostProcessor processor : context.getQueryStringPostProcessors())
+        {
+            if (processor instanceof OrderByQueryStringPostProcessor)
+            {
+                OrderByQueryStringPostProcessor orderBy = (OrderByQueryStringPostProcessor) processor;
+                if (changeOrder.matches(orderBy))
+                {
+                    orderBy.changeDirection();
+                    return this;
+                }
+            }
+        }
+        changeOrder.addDefault();
+        return this;
+    }
+
+    private abstract static class ChangeOrder
+    {
+
+        public abstract boolean matches(OrderByQueryStringPostProcessor orderBy);
+
+        public abstract void addDefault();
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessor.java
new file mode 100644
index 0000000..b39b9ee
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessor.java
@@ -0,0 +1,28 @@
+/*
+ * 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.deltaspike.data.impl.builder.result;
+
+import javax.persistence.Query;
+
+public interface QueryProcessor
+{
+
+    Object executeQuery(Query query);
+
+}

http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java
new file mode 100644
index 0000000..4b14616
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/builder/result/QueryProcessorFactory.java
@@ -0,0 +1,122 @@
+/*
+ * 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.deltaspike.data.impl.builder.result;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.api.Modifying;
+import org.apache.deltaspike.data.api.QueryResult;
+
+public final class QueryProcessorFactory
+{
+
+    private final Method method;
+
+    private QueryProcessorFactory(Method method)
+    {
+        this.method = method;
+    }
+
+    public static QueryProcessorFactory newInstance(Method method)
+    {
+        return new QueryProcessorFactory(method);
+    }
+
+    public QueryProcessor build()
+    {
+        if (returns(QueryResult.class))
+        {
+            return new NoOpQueryProcessor();
+        }
+        if (returns(List.class))
+        {
+            return new ListQueryProcessor();
+        }
+        if (isModifying())
+        {
+            return new ExecuteUpdateQueryProcessor(returns(Void.TYPE));
+        }
+        return new SingleResultQueryProcessor();
+    }
+
+    private boolean isModifying()
+    {
+        boolean matchesType = Void.TYPE.equals(method.getReturnType()) ||
+                int.class.equals(method.getReturnType()) ||
+                Integer.class.equals(method.getReturnType());
+        return method.isAnnotationPresent(Modifying.class) && matchesType;
+    }
+
+    private boolean returns(Class<?> clazz)
+    {
+        return method.getReturnType().isAssignableFrom(clazz);
+    }
+
+    private static final class ListQueryProcessor implements QueryProcessor
+    {
+        @Override
+        public Object executeQuery(Query query)
+        {
+            return query.getResultList();
+        }
+    }
+
+    private static final class NoOpQueryProcessor implements QueryProcessor
+    {
+        @Override
+        public Object executeQuery(Query query)
+        {
+            return query;
+        }
+    }
+
+    private static final class SingleResultQueryProcessor implements QueryProcessor
+    {
+        @Override
+        public Object executeQuery(Query query)
+        {
+            return query.getSingleResult();
+        }
+    }
+
+    private static final class ExecuteUpdateQueryProcessor implements QueryProcessor
+    {
+
+        private final boolean returnsVoid;
+
+        private ExecuteUpdateQueryProcessor(boolean returnsVoid)
+        {
+            this.returnsVoid = returnsVoid;
+        }
+
+        @Override
+        public Object executeQuery(Query query)
+        {
+            int result = query.executeUpdate();
+            if (!returnsVoid)
+            {
+                return result;
+            }
+            return null;
+        }
+    }
+}