Repository: cayenne
Updated Branches:
  refs/heads/master 831442cb6 -> fb7f004a8


CAY-2481 Methods to return Object[] after SQLTemplate and SQLExec perform


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/18c72d34
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/18c72d34
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/18c72d34

Branch: refs/heads/master
Commit: 18c72d34710646bed3c51a6b64285a597a56c2b6
Parents: 553de26
Author: Arseni Bulatski <ancars...@gmail.com>
Authored: Wed Oct 24 09:26:36 2018 +0300
Committer: Arseni Bulatski <ancars...@gmail.com>
Committed: Wed Oct 24 12:04:14 2018 +0300

----------------------------------------------------------------------
 .../access/jdbc/RowDescriptorBuilder.java       |   2 +-
 .../cayenne/access/jdbc/SQLTemplateAction.java  |  26 +-
 .../cayenne/map/DefaultScalarResultSegment.java |   4 +-
 .../org/apache/cayenne/query/SQLSelect.java     |  84 ++++++-
 .../org/apache/cayenne/query/SQLTemplate.java   |  17 +-
 .../cayenne/query/SQLTemplateMetadata.java      |  29 ++-
 .../org/apache/cayenne/query/SQLSelectIT.java   |  84 ++++++-
 .../org/apache/cayenne/query/SQLTemplateIT.java | 241 ++++++++++++++++++-
 8 files changed, 452 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
index 6c92c12..7ab51b7 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/RowDescriptorBuilder.java
@@ -106,7 +106,7 @@ public class RowDescriptorBuilder {
             throw new CayenneRuntimeException("Size of 'ResultSetMetadata' not 
equals to size of 'columns'.");
         } else if (rsLen < columnLen) {
             throw new CayenneRuntimeException("'ResultSetMetadata' has less 
elements then 'columns'.");
-        } else if (rsLen == columnLen && !mergeColumnsWithRsMetadata) {
+        } else if(rsLen == columnLen && !mergeColumnsWithRsMetadata) {
             // 'columns' contains ColumnDescriptor for every column
             // in resultSetMetadata. This return is for optimization.
             return columns;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
index cc6ac56..2f27eb0 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
@@ -20,6 +20,7 @@
 package org.apache.cayenne.access.jdbc;
 
 import org.apache.cayenne.CayenneException;
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ResultIterator;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.OperationObserver;
@@ -31,6 +32,7 @@ import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DefaultScalarResultSegment;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.query.QueryMetadata;
@@ -250,8 +252,8 @@ public class SQLTemplateAction implements SQLAction {
                boolean iteratedResult = callback.isIteratedResult();
                ExtendedTypeMap types = 
dataNode.getAdapter().getExtendedTypes();
                RowDescriptorBuilder builder = 
configureRowDescriptorBuilder(compiled, resultSet);
+               recreateQueryMetadata(resultSet);
                RowReader<?> rowReader = 
dataNode.rowReader(builder.getDescriptor(types), queryMetadata);
-
                ResultIterator<?> it = new JDBCResultIterator<>(statement, 
resultSet, rowReader);
 
                if (iteratedResult) {
@@ -286,13 +288,25 @@ public class SQLTemplateAction implements SQLAction {
                }
        }
 
+       private void recreateQueryMetadata(ResultSet resultSet) throws 
SQLException {
+               if(query.isUseScalar() && queryMetadata.getResultSetMapping() 
!= null && queryMetadata.getResultSetMapping().isEmpty()){
+                       for(int i = 0; i < 
resultSet.getMetaData().getColumnCount(); i++) {
+                               queryMetadata.getResultSetMapping().add(new 
DefaultScalarResultSegment(String.valueOf(i), i));
+                       }
+               }
+       }
+
        /**
         * Creates column descriptors based on compiled statement and query 
metadata
         */
        private ColumnDescriptor[] createColumnDescriptors(SQLStatement 
compiled) {
                // SQLTemplate #result columns take precedence over other ways 
to determine the type
                if (compiled.getResultColumns().length > 0) {
-                       return compiled.getResultColumns();
+                       if(query.getResultColumnsTypes() != null) {
+                               throw new CayenneRuntimeException("Caused by 
setting return types by directives and by parameters in query.");
+                       } else {
+                               return compiled.getResultColumns();
+                       }
                }
 
                // check explicitly set column types
@@ -325,7 +339,7 @@ public class SQLTemplateAction implements SQLAction {
                }
 
                ObjEntity entity = queryMetadata.getObjEntity();
-               if (entity != null) {
+               if (entity != null && isResultColumnTypesEmpty()) {
                        // TODO: andrus 2008/03/28 support flattened attributes 
with aliases...
                        for (ObjAttribute attribute : entity.getAttributes()) {
                                String column = attribute.getDbAttributePath();
@@ -339,7 +353,7 @@ public class SQLTemplateAction implements SQLAction {
                // override numeric Java types based on JDBC defaults for 
DbAttributes, as Oracle
                // ResultSetMetadata is not very precise about NUMERIC 
distinctions...
                // (BigDecimal vs Long vs. Integer)
-               if (dbEntity != null) {
+               if (dbEntity != null && isResultColumnTypesEmpty()) {
                        for (DbAttribute attribute : dbEntity.getAttributes()) {
                                if (!builder.isOverriden(attribute.getName()) 
&& TypesMapping.isNumeric(attribute.getType())) {
                                        
builder.overrideColumnType(attribute.getName(), 
TypesMapping.getJavaBySqlType(attribute.getType()));
@@ -359,6 +373,10 @@ public class SQLTemplateAction implements SQLAction {
                return builder;
        }
 
+       private boolean isResultColumnTypesEmpty(){
+               return query.getResultColumnsTypes() == null || 
query.getResultColumnsTypes().isEmpty();
+       }
+
        /**
         * Extracts a template string from a SQLTemplate query. Exists mainly 
for
         * the benefit of subclasses that can customize returned template.

http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/main/java/org/apache/cayenne/map/DefaultScalarResultSegment.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/map/DefaultScalarResultSegment.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/map/DefaultScalarResultSegment.java
index 1b25684..b0933dd 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/map/DefaultScalarResultSegment.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/map/DefaultScalarResultSegment.java
@@ -23,12 +23,12 @@ import org.apache.cayenne.query.ScalarResultSegment;
 /**
  * @since 3.0
  */
-class DefaultScalarResultSegment implements ScalarResultSegment {
+public class DefaultScalarResultSegment implements ScalarResultSegment {
 
     private String column;
     private int offset;
 
-    DefaultScalarResultSegment(String column, int offset) {
+    public DefaultScalarResultSegment(String column, int offset) {
         this.column = column;
         this.offset = offset;
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
index 3d46f6a..c276a78 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
@@ -29,7 +29,6 @@ import org.apache.cayenne.map.EntityResolver;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -45,12 +44,34 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        private static final long serialVersionUID = -7074293371883740872L;
 
        private List<Class<?>> resultColumnsTypes;
+       private boolean useScalar;
+       private boolean isFetchingDataRows;
 
        /**
         * Creates a query that selects DataRows and uses default routing.
         */
        public static SQLSelect<DataRow> dataRowQuery(String sql) {
-               return new SQLSelect<>(sql);
+               return new SQLSelect<>(sql)
+                               .fetchingDataRows();
+       }
+
+       /**
+        * Creates a query that selects DataRows and uses default routing.
+        * @since 4.1
+        */
+       public static SQLSelect<DataRow> dataRowQuery(String sql, Class<?>... 
types) {
+               return new SQLSelect<>(sql)
+                               .resultColumnsTypes(types)
+                               .fetchingDataRows();
+       }
+
+       /**
+        * Creates a query that selects DataRows and uses routing based on the
+        * provided DataMap name.
+        * @since 4.1
+        */
+       public static SQLSelect<DataRow> dataRowQuery(String dataMapName, 
String sql, Class<?>... types) {
+               return dataRowQuery(dataMapName, sql).resultColumnsTypes(types);
        }
 
        /**
@@ -60,7 +81,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        public static SQLSelect<DataRow> dataRowQuery(String dataMapName, 
String sql) {
                SQLSelect<DataRow> query = new SQLSelect<>(sql);
                query.dataMapName = dataMapName;
-               return query;
+               return query.fetchingDataRows();
        }
 
        /**
@@ -84,7 +105,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        public static <T> SQLSelect<T> scalarQuery(Class<T> type, String 
dataMapName, String sql) {
                SQLSelect<T> query = new SQLSelect<>(sql);
                query.dataMapName = dataMapName;
-               return query.resultColumnsTypes(type);
+               return query.resultColumnsTypes(type).useScalar();
        }
 
        /**
@@ -94,7 +115,39 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
         */
        public static <T> SQLSelect<T> scalarQuery(String sql, Class<T> type) {
                SQLSelect<T> query = new SQLSelect<>(sql);
-               return query.resultColumnsTypes(type);
+               return query.resultColumnsTypes(type).useScalar();
+       }
+
+       /**
+        * Creates query that selects scalar value and uses default routing
+        *
+        * @since 4.1
+        */
+       public static <T> SQLSelect<T> scalarQuery(String sql, String 
dataMapName, Class<T> type) {
+               SQLSelect<T> query = new SQLSelect<>(sql);
+               query.dataMapName = dataMapName;
+               return query.resultColumnsTypes(type).useScalar();
+       }
+
+       /**
+        * Creates query that selects scalar value and uses default routing
+        *
+        * @since 4.1
+        */
+       public static SQLSelect<Object[]> scalarQuery(String sql) {
+               SQLSelect<Object[]> query = new SQLSelect<>(sql);
+               return query.useScalar();
+       }
+
+       /**
+        * Creates query that selects scalar values (as Object[]) and uses 
routing based on the
+        * provided DataMap name.
+        * @since 4.1
+        */
+       public static SQLSelect<Object[]> scalarQuery(String sql, String 
dataMapName) {
+               SQLSelect<Object[]> query = new SQLSelect<>(sql);
+               query.dataMapName = dataMapName;
+               return query.useScalar();
        }
 
        /**
@@ -104,7 +157,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
         */
        public static SQLSelect<Object[]> scalarQuery(String sql, Class<?> 
firstType, Class<?>... types) {
                SQLSelect<Object[]> query = new SQLSelect<>(sql);
-               return 
query.resultColumnsTypes(firstType).resultColumnsTypes(types);
+               return 
query.resultColumnsTypes(firstType).resultColumnsTypes(types).useScalar();
        }
 
        /**
@@ -116,7 +169,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        public static SQLSelect<Object[]> scalarQuery(String sql, String 
dataMapName, Class<?> firstType, Class<?>... types) {
                SQLSelect<Object[]> query = new SQLSelect<>(sql);
                query.dataMapName = dataMapName;
-               return 
query.resultColumnsTypes(firstType).resultColumnsTypes(types);
+               return 
query.resultColumnsTypes(firstType).resultColumnsTypes(types).useScalar();
        }
 
        @SuppressWarnings("unchecked")
@@ -185,7 +238,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        }
 
        public boolean isFetchingDataRows() {
-               return persistentType == null;
+               return isFetchingDataRows;
        }
 
        public String getSql() {
@@ -291,7 +344,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
                }
 
                SQLTemplate template = new SQLTemplate();
-               template.setFetchingDataRows(isFetchingDataRows());
+               template.setFetchingDataRows(isFetchingDataRows);
                template.setRoot(root);
                template.setDefaultTemplate(getSql());
                template.setCacheGroup(cacheGroup);
@@ -312,6 +365,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
                template.setFetchOffset(offset);
                template.setPageSize(pageSize);
                template.setStatementFetchSize(statementFetchSize);
+               template.setUseScalar(useScalar);
 
                return template;
        }
@@ -534,4 +588,16 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
                prefetches.merge(node);
                return this;
        }
+
+       @SuppressWarnings("unchecked")
+       private <E> SQLSelect<E> fetchingDataRows() {
+               this.isFetchingDataRows = true;
+               return (SQLSelect<E>) this;
+       }
+
+       @SuppressWarnings("unchecked")
+       private <E> SQLSelect<E> useScalar() {
+               this.useScalar = true;
+               return (SQLSelect<E>) this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
index fa863c3..55a590d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
@@ -84,6 +84,7 @@ public class SQLTemplate extends AbstractQuery implements 
ParameterizedQuery {
        protected boolean returnGeneratedKeys;
 
        private List<Class<?>> resultColumnsTypes;
+       private boolean useScalar;
 
        SQLTemplateMetadata metaData = new SQLTemplateMetadata();
 
@@ -108,12 +109,11 @@ public class SQLTemplate extends AbstractQuery implements 
ParameterizedQuery {
                setFetchingDataRows(isFetchingDataRows);
        }
 
-       public SQLTemplate resultColumnsTypes(Class<?> ...types) {
+       public void setResultColumnsTypes(Class<?> ...types) {
                if(resultColumnsTypes == null) {
                        resultColumnsTypes = new ArrayList<>(types.length);
                }
                Collections.addAll(resultColumnsTypes, types);
-               return this;
        }
 
        @Override
@@ -671,4 +671,17 @@ public class SQLTemplate extends AbstractQuery implements 
ParameterizedQuery {
        public void setResultColumnsTypes(List<Class<?>> resultColumnsTypes) {
                this.resultColumnsTypes = resultColumnsTypes;
        }
+
+       /**
+        * Sets flag to use scalars.
+        *
+        * @since 4.1
+        */
+       public void setUseScalar(boolean useScalar) {
+           this.useScalar = useScalar;
+       }
+
+       public boolean isUseScalar() {
+               return useScalar;
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java
index 1537f8a..3cd99a4 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplateMetadata.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.query;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.SQLResult;
@@ -30,14 +31,36 @@ import java.util.Map;
 /**
  * @since 3.0
  */
-class SQLTemplateMetadata extends BaseQueryMetadata {
+public class SQLTemplateMetadata extends BaseQueryMetadata {
+
+       private boolean isSingleResultSetMapping;
+
+       @Override
+       public boolean isSingleResultSetMapping() {
+               return isSingleResultSetMapping;
+       }
 
        boolean resolve(Object root, EntityResolver resolver, SQLTemplate 
query) {
 
                if (super.resolve(root, resolver)) {
 
+                       if((!query.isUseScalar() && 
!query.isFetchingDataRows()) && (query.getResultColumnsTypes() != null && 
!query.getResultColumnsTypes().isEmpty())) {
+                               throw new CayenneRuntimeException("Error caused 
by using root in query with resultColumnTypes without scalar or dataRow.");
+                       }
+
+                       if(query.getResult() != null && 
query.getResultColumnsTypes() != null) {
+                               throw new CayenneRuntimeException("Caused by 
trying to override result column types of query.");
+                       }
+
+                       if(query.isFetchingDataRows() && query.isUseScalar()) {
+                               throw new CayenneRuntimeException("Can't set 
both use scalar and fetching data rows.");
+                       }
+
                        buildResultSetMappingForColumns(query);
-                       resultSetMapping = query.getResult() != null ? 
query.getResult().getResolvedComponents(resolver) : null;
+                       resultSetMapping = query.getResult() != null ?
+                                       
query.getResult().getResolvedComponents(resolver) :
+                                       query.isUseScalar() ? new ArrayList<>() 
: null;
+                       isSingleResultSetMapping = resultSetMapping != null && 
resultSetMapping.size() == 1;
 
                        // generate unique cache key...
                        if (QueryCacheStrategy.NO_CACHE == getCacheStrategy()) {
@@ -93,7 +116,7 @@ class SQLTemplateMetadata extends BaseQueryMetadata {
        }
 
        private void buildResultSetMappingForColumns(SQLTemplate query) {
-               if(query.getResultColumnsTypes() == null || 
query.getResultColumnsTypes().isEmpty()) {
+               if(query.getResultColumnsTypes() == null || 
query.getResultColumnsTypes().isEmpty() || !query.isUseScalar()) {
                        return;
                }
                SQLResult result = new SQLResult();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java 
b/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
index 7774c8c..cbc7c83 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
@@ -43,6 +43,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.*;
 
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
@@ -114,15 +115,90 @@ public class SQLSelectIT extends ServerCase {
        }
 
        @Test
-       public void test_ObjectArrayQuery() throws Exception {
+       public void test_DataRowWithTypes() throws Exception {
+               tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
+               tArtistCt.insert(2, "Test1", new 
Date(System.currentTimeMillis()));
+               List<DataRow> result = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST_CT", Integer.class, String.class, LocalDateTime.class)
+                               .columnNameCaps(CapsStrategy.UPPER)
+                               .select(context);
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof DataRow);
+               assertThat(result.get(0).get("DATE_OF_BIRTH"), 
instanceOf(LocalDateTime.class));
+       }
+
+       @Test
+       public void test_DataRowWithDirectives() throws Exception {
+               tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
+               tArtistCt.insert(2, "Test1", new 
Date(System.currentTimeMillis()));
+               List<DataRow> result = SQLSelect.dataRowQuery("SELECT 
#result('ARTIST_ID' 'java.lang.Double'), #result('ARTIST_NAME' 
'java.lang.String') FROM ARTIST_CT")
+                               .select(context);
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof DataRow);
+               assertTrue(result.get(0).get("ARTIST_ID") instanceof Double);
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void test_DataRowWithTypesException() throws Exception {
+               tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
+               SQLSelect.dataRowQuery("SELECT * FROM ARTIST_CT", 
Integer.class, String.class)
+                               .select(context);
+       }
+
+       @Test
+       public void testObjectArrayWithDefaultTypesReturnAndDirectives() throws 
Exception {
+               tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
+               tArtistCt.insert(2, "Test1", new 
Date(System.currentTimeMillis()));
+               List<Object[]> result = SQLSelect.scalarQuery("SELECT 
#result('ARTIST_ID' 'java.lang.Long'), #result('ARTIST_NAME' 
'java.lang.String') FROM ARTIST_CT")
+                               .select(context);
+
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof Object[]);
+               assertEquals(2, result.get(0).length);
+               assertTrue(result.get(0)[0] instanceof Long);
+               assertTrue(result.get(0)[1] instanceof String);
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void testObjectArrayReturnAndDirectives() throws Exception {
+               tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
+               tArtistCt.insert(2, "Test1", new 
Date(System.currentTimeMillis()));
+               SQLSelect.scalarQuery("SELECT #result('ARTIST_ID' 
'java.lang.Long'), #result('ARTIST_NAME' 'java.lang.String') FROM ARTIST_CT",
+                               Integer.class, String.class).select(context);
+       }
+
+       @Test
+       public void 
testObjectArrayWithOneObjectDefaultTypesReturnAndDirectives() throws Exception {
+               tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
+               tArtistCt.insert(2, "Test1", new 
Date(System.currentTimeMillis()));
+               List<Object[]> result = SQLSelect.scalarQuery("SELECT 
#result('ARTIST_ID' 'java.lang.Long') FROM ARTIST_CT")
+                               .select(context);
+
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof Object[]);
+               assertEquals(1, result.get(0).length);
+               assertTrue(result.get(0)[0] instanceof Long);
+       }
+
+       @Test
+       public void test_ObjectArrayQueryWithDefaultTypes() throws Exception {
                createPaintingsDataSet();
-               List<Object[]> result = SQLSelect.scalarQuery("SELECT 
PAINTING_ID, PAINTING_TITLE, ESTIMATED_PRICE FROM PAINTING", Integer.class, 
String.class, Double.class)
+               List<Object[]> result = SQLSelect.scalarQuery("SELECT 
PAINTING_ID, PAINTING_TITLE, ESTIMATED_PRICE FROM PAINTING")
                                .select(context);
 
                assertEquals(20, result.size());
                assertEquals(3, result.get(0).length);
        }
 
+       @Test
+       public void test_ObjectQueryWithDefaultType() throws Exception {
+               createPaintingsDataSet();
+               List<Object[]> result = SQLSelect.scalarQuery("SELECT 
PAINTING_ID FROM PAINTING")
+                               .select(context);
+               assertEquals(20, result.size());
+               assertTrue(result.get(0) instanceof Object[]);
+               assertTrue(result.get(0)[0] instanceof Integer);
+       }
+
        @Test(expected = CayenneRuntimeException.class)
        public void test_ObjectArrayQueryException() throws Exception {
                createPaintingsDataSet();
@@ -148,6 +224,7 @@ public class SQLSelectIT extends ServerCase {
                                Integer.class, String.class, 
LocalDateTime.class).select(context);
 
                assertEquals(2, results.size());
+               assertTrue(results.get(0) instanceof Object[]);
                assertEquals(3, results.get(0).length);
                assertTrue(results.get(0)[2] instanceof LocalDateTime);
        }
@@ -353,8 +430,7 @@ public class SQLSelectIT extends ServerCase {
 
                createPaintingsDataSet();
 
-               int c = SQLSelect.scalarQuery(Integer.class, "SELECT 
#result('COUNT(*)' 'int') FROM PAINTING").selectOne(
-                               context);
+               int c = SQLSelect.scalarQuery("SELECT COUNT(*) FROM PAINTING", 
Integer.class).selectOne(context);
 
                assertEquals(20, c);
        }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/18c72d34/cayenne-server/src/test/java/org/apache/cayenne/query/SQLTemplateIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/query/SQLTemplateIT.java 
b/cayenne-server/src/test/java/org/apache/cayenne/query/SQLTemplateIT.java
index 9931f8c..da4fff4 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/SQLTemplateIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/SQLTemplateIT.java
@@ -25,8 +25,10 @@ import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.SQLResult;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Gallery;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.UnitDbAdapter;
@@ -42,6 +44,7 @@ import java.sql.SQLException;
 import java.time.LocalDateTime;
 import java.util.List;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.*;
 
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
@@ -134,18 +137,232 @@ public class SQLTemplateIT extends ServerCase {
        }
 
        @Test(expected = CayenneRuntimeException.class)
+       public void testExceptionWhenUsingColumnsTypesAndSQLResult(){
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate query = new SQLTemplate("SELECT ARTIST_ID P FROM 
ARTIST", true);
+               query.setResultColumnsTypes(Float.class);
+               SQLResult resultDescriptor = new SQLResult();
+               resultDescriptor.addColumnResult("P");
+               query.setResult(resultDescriptor);
+               context.performQuery(query);
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void testExceptionWhenUsingColumnsTypesAndSQLResultUsingScalar() 
{
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate query = new SQLTemplate(testDataMap, "SELECT 
ARTIST_ID, ARTIST_NAME P FROM ARTIST", false);
+               query.setResultColumnsTypes(Float.class, String.class);
+               query.setUseScalar(true);
+               SQLResult resultDescriptor = new SQLResult();
+               resultDescriptor.addColumnResult("P");
+               resultDescriptor.addColumnResult("N");
+               query.setResult(resultDescriptor);
+               context.performQuery(query);
+       }
+
+       @Test
+       public void testWithRootUsingScalar() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+               SQLTemplate q3 = new SQLTemplate(Artist.class, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST");
+               q3.setResultColumnsTypes(Double.class, String.class);
+               q3.setUseScalar(true);
+               List<Object[]> result = context.performQuery(q3);
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof Object[]);
+               assertTrue(result.get(0)[0] instanceof Double);
+       }
+
+       @Test
+       public void testWithRootUsingDataRow() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+               SQLTemplate q3 = new SQLTemplate(Artist.class, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST");
+               q3.setResultColumnsTypes(Double.class, String.class);
+               q3.setFetchingDataRows(true);
+               q3.setColumnNamesCapitalization(CapsStrategy.UPPER);
+               List<DataRow> result = context.performQuery(q3);
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof DataRow);
+               assertThat(result.get(0).get("ARTIST_ID"), 
instanceOf(Double.class));
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void testWithRootException() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q3 = new SQLTemplate(Artist.class, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST");
+               q3.setResultColumnsTypes(Double.class, String.class);
+               context.performQuery(q3);
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void testUsingScalarAndDataRow() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q3 = new SQLTemplate(Artist.class, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST");
+               q3.setUseScalar(true);
+               q3.setFetchingDataRows(true);
+               context.performQuery(q3);
+       }
+
+       @Test
+       public void testDataRowWithTypes() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST", true);
+               q3.setResultColumnsTypes(Double.class, String.class);
+               q3.setColumnNamesCapitalization(CapsStrategy.UPPER);
+               List<DataRow> artists = context.performQuery(q3);
+               assertEquals(2, artists.size());
+               assertTrue(artists.get(0) instanceof DataRow);
+               assertThat(artists.get(0).get("ARTIST_ID"), 
instanceOf(Double.class));
+       }
+
+       @Test
+       public void testDataRowReturnAndDirectives() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
#result('ARTIST_ID' 'java.lang.Long'), #result('ARTIST_NAME' 
'java.lang.String') FROM ARTIST", true);
+               List<DataRow> result = context.performQuery(q3);
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof DataRow);
+               assertEquals(2, result.get(0).size());
+               assertTrue(result.get(0).get("ARTIST_ID") instanceof Long);
+               assertTrue(result.get(0).get("ARTIST_NAME") instanceof String);
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void testDataRowReturnAndDirectivesExc() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
#result('ARTIST_ID' 'java.lang.Long'), #result('ARTIST_NAME' 
'java.lang.String') FROM ARTIST", true);
+               q3.setResultColumnsTypes(Integer.class, String.class);
+               context.performQuery(q3);
+       }
+
+       @Test
+       public void testObjectArrayReturnAndDirectives() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
#result('ARTIST_ID' 'java.lang.Long'), #result('ARTIST_NAME' 
'java.lang.String') FROM ARTIST", false);
+               q3.setUseScalar(true);
+               List<Object[]> result = context.performQuery(q3);
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof Object[]);
+               assertEquals(2, result.get(0).length);
+               assertTrue(result.get(0)[0] instanceof Long);
+               assertTrue(result.get(0)[1] instanceof String);
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
+       public void testObjectArrayReturnAndDirectivesException() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
#result('ARTIST_ID' 'java.lang.Long'), #result('ARTIST_NAME' 
'java.lang.String') FROM ARTIST", false);
+               q3.setResultColumnsTypes(Integer.class, String.class);
+               q3.setUseScalar(true);
+               context.performQuery(q3);
+       }
+
+       @Test
+       public void testObjectArrayWithSingleObjectReturnAndDirectives() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
#result('ARTIST_ID' 'java.lang.Long') FROM ARTIST", false);
+               q3.setUseScalar(true);
+               List<Object[]> result = context.performQuery(q3);
+               assertEquals(2, result.size());
+               assertTrue(result.get(0) instanceof Object[]);
+               assertEquals(1, result.get(0).length);
+               assertTrue(result.get(0)[0] instanceof Long);
+       }
+
+       @Test(expected = CayenneRuntimeException.class)
        public void testObjectArrayReturnWithException() {
                DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
                String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
                SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
                context.performNonSelectingQuery(q1);
-               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST", true)
-                               .resultColumnsTypes(Integer.class);
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST", false);
+               q3.setResultColumnsTypes(Integer.class);
+               q3.setUseScalar(true);
                context.performQuery(q3);
        }
 
        @Test
-       public void testObjectArrayReturn() throws SQLException {
+       public void testObjectArrayWithSingleObjectReturn() {
+               DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
+               String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
+               String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
+               SQLTemplate q1 = new SQLTemplate(testDataMap, sql, true);
+               context.performNonSelectingQuery(q1);
+               SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
+               context.performNonSelectingQuery(q2);
+
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT ARTIST_ID 
FROM ARTIST", false);
+               q3.setUseScalar(true);
+               List<Object[]> artists = context.performQuery(q3);
+               assertEquals(2, artists.size());
+               assertEquals(1, artists.get(0).length);
+               assertTrue(artists.get(0) instanceof Object[]);
+               assertTrue(artists.get(0)[0] instanceof Long);
+       }
+
+       @Test
+       public void testObjectArrayReturnWithDefaultTypes() {
                DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
                String sql = "INSERT INTO ARTIST VALUES (15, 'Surikov', null)";
                String sql1 = "INSERT INTO ARTIST VALUES (16, 'Ivanov', null)";
@@ -154,20 +371,23 @@ public class SQLTemplateIT extends ServerCase {
                SQLTemplate q2 = new SQLTemplate(testDataMap, sql1, true);
                context.performNonSelectingQuery(q2);
 
-               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST", true)
-                               .resultColumnsTypes(Integer.class, 
String.class);
+               SQLTemplate q3 = new SQLTemplate(testDataMap, "SELECT 
ARTIST_ID, ARTIST_NAME FROM ARTIST", false);
+               q3.setUseScalar(true);
                List<Object[]> artists = context.performQuery(q3);
                assertEquals(2, artists.size());
                assertEquals(2, artists.get(0).length);
+               assertTrue(artists.get(0) instanceof Object[]);
+               assertTrue(artists.get(0)[0] instanceof Long);
        }
 
        @Test
-       public void testObjectArrayReturnWithCustomType() throws SQLException {
+       public void testObjectArrayReturn() throws SQLException {
                DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
                tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
                tArtistCt.insert(2, "Test1", new 
Date(System.currentTimeMillis()));
-               SQLTemplate q5 = new SQLTemplate(testDataMap, "SELECT * FROM 
ARTIST_CT", true)
-                               .resultColumnsTypes(Integer.class, 
String.class, LocalDateTime.class);
+               SQLTemplate q5 = new SQLTemplate(testDataMap, "SELECT * FROM 
ARTIST_CT", false);
+               q5.setResultColumnsTypes(Float.class, String.class, 
LocalDateTime.class);
+               q5.setUseScalar(true);
                List dates = context.performQuery(q5);
                assertEquals(2, dates.size());
                assertTrue(dates.get(0) instanceof Object[]);
@@ -179,8 +399,9 @@ public class SQLTemplateIT extends ServerCase {
        public void testSingleObjectReturn() throws SQLException {
                DataMap testDataMap = 
context.getEntityResolver().getDataMap("testmap");
                tArtistCt.insert(1, "Test", new 
Date(System.currentTimeMillis()));
-               SQLTemplate q5 = new SQLTemplate(testDataMap, "SELECT 
ARTIST_NAME FROM ARTIST_CT", true)
-                               .resultColumnsTypes(String.class);
+               SQLTemplate q5 = new SQLTemplate(testDataMap, "SELECT 
ARTIST_NAME FROM ARTIST_CT", false);
+               q5.setResultColumnsTypes(String.class);
+               q5.setUseScalar(true);
                List dates = context.performQuery(q5);
                assertEquals(1, dates.size());
                assertTrue(dates.get(0) instanceof String);

Reply via email to